7

I have an action method that uses my authentication filter:

public class TutorAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        var auth = req.Headers["Authorization"];
        if (!string.IsNullOrEmpty(auth))
        {
            var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
            var user = new { Name = cred[0], Password = cred[1] };
            if (userService.AuthorizeTutor(user.Name, user.Password))
            {
                return;
            }
        }
        filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", $"Basic realm= {BasicRealm}");

        filterContext.Result = new HttpUnauthorizedResult();
    }
}

I would like to then display on main page something for user that have been authenticated this way, but this does not work in my View :(

@if (Request.IsAuthenticated)
{
    <h1>Hello</h1>
}

I know it does not work because I don't use Identity, but is there any way that I can do this?

Thank you for answers :)

9
  • From where userService came from? Does it have some property which can retururns authenticated state? Commented Dec 23, 2016 at 20:19
  • DI, I just omitted some not important properties... it just returns true/false Commented Dec 23, 2016 at 20:21
  • that filter automatically stores some data into cookies so there is authenticated state stored Commented Dec 23, 2016 at 20:24
  • do you have mind if the solution used 'Identity' ?? Commented Dec 26, 2016 at 14:48
  • 1
    When you say you would like a solution without Identity, does that also leaves out the possibility of setting Thread.CurrentPrincipal to a GenericPrincipal? Commented Jan 2, 2017 at 3:28

5 Answers 5

4
+50

I suppose, that sending login and password in header is not secure. Better solution is one time when user is verified. And after checking, you can check all request.

For example, if you use FormsAuthentication and authCookie it's very simple:

  1. Set auth mentod in web.config: <authentication mode="Forms" />

  2. When login and password is valid, use FormsAuthentication.SetAuthCookie(userName, createPersistentCookie = true); This step is performed only once, when user login to application.

  3. Then you can use property this.Request.IsAuthenticated in view or HttpContext.Current.Request.IsAuthenticated in controller (or filter).

  4. And it works attribute [Authorize] on conntrolers or actions (public methods in conntrollers). When request is not authenticated, request is redirected to default (or set in web.config) login page.

Sign up to request clarification or add additional context in comments.

2 Comments

I don't think that sending login and password in header is not secure (when you use HTTPS). I will try to check some documents about FormsAuthentication if it solves my problem :)
This works very nice, but I found an article about that FormsAuthentication is obsolete because it does not run on Owin (which doesn't matter in my case)
4

Create a new extension method for the request object say (IsUserAuthenticated()) & in that method check if the user is valid. Once this is done, you can use this new extension method the same way you are using Request.IsAuthenticated Property.

Below is the sample code, which you will need to tweak as per your needs. (specifically for

userservice 

initialization)

public class RequestValidator
{
    public bool IsValid(HttpRequest request)
    {
       bool isValid  = false;

       //TODO: Intitialize your userService here, may be using DI or a concrete object creation depending on your implementation

       var auth = request.Headers["Authorization"];
       if (!string.IsNullOrEmpty(auth))
       {
           var cred = System.Text.Encoding.ASCII.GetString(Convert.FromBase64String(auth.Substring(6))).Split(':');
           var user = new { Name = cred[0], Password = cred[1] };

           isValid = userService.AuthorizeTutor(user.Name, user.Password))            
       }

      return isValid; 
    }
}

Your attribute will change like this

public class TutorAuthenticationAttribute : ActionFilterAttribute
{
    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var req = filterContext.HttpContext.Request;
        RequestValidator validator = new RequestValidator(); 
        if(validator.IsValid(request))
        {
            return; 
        }

        filterContext.HttpContext.Response.AddHeader("WWW-Authenticate", $"Basic realm= {BasicRealm}");

        filterContext.Result = new HttpUnauthorizedResult();
    }
}

And the extension method to be used on view will be

public static class Extensions
{
    public static bool IsUserAuthenticated(this HttpRequest request)
    {
        RequestValidator validator = new RequestValidator(); 
        return validator.IsValid(request); 
    }
}

Use it like this

@if(Request.IsUserAuthenticated())
{
     <p>Hello</p>
}

3 Comments

But how can I check, if the user is valid?
Thank you for your answer, but this does not work properly. Hello is only displayed on pages that demand authentization - I need to display it even on other pages after the user typed correct username and password. ( I have a feeling maybe I need to somehow access cookies that it indirectly uses?)
You can replace the authorization code with cookies.
1

If you want to pass the boolean value indicating if the user is authenticated, maybe it makes sense to just use the model object and pass it to the view.

Or maybe you should review your Form Authentication to make Request.IsAuthenticated working properly. This thread will help to start digging.

Another option would be to consider using the IAuthorizationFilter instead of the custom action filter. This thread will be a starting point.

Hope that helps!

1 Comment

Thanks, I used second option (as suggested by ksciana before), I don't think that other options will solve the problem
1

To meet your purpose, you would need to set HttpContext.User to some valid IPrincipal. So, if according to your criteria, the user is valid you just need to create a GenericPrinicpal and set HttpContext.User with the instance you have just created.

Something like this:

var genericIdentity=new GenericIdentity(user.Name,  "CustomAuthType");
var genericPrincipal=new GenericPrincipal(genericIdentity, null);

HttpContext.User = genericPrincipal;

With GenericIdentity, the value of IsAuthenticated is dependent on the Name property, so as soon as the GenericIdentity has a Name, it is considered to be authenticated.

In this example, I'm setting the HttpContext.User and not the Thread.CurrentPrincipal so that you can get the IsAuthenticated from the Request.IsAuthenticated property.

Some extra and related information:

GenericIdentity Class

Principal and Identity Objects

Create GenericPrincipal and GenericIdentity Objects

Replacing a Principal Object

1 Comment

Thank you for interesting answer, I will look into it more and let everyone know if and how it solves the problem :) Unfortunately I won't have enough time to award you the bounty because it ends tomorrow
0

in your startup.cs file add this

app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Login"),

            SlidingExpiration = true,
            ExpireTimeSpan = TimeSpan.FromMinutes(40)


        });

1 Comment

Thanks, but just this won't work with my custom authentication

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.