How do you create a custom AuthorizeAttribute in ASP.NET Core?

前端 未结 11 1207
春和景丽
春和景丽 2020-11-21 17:19

I\'m trying to make a custom authorization attribute in ASP.NET Core. In previous versions it was possible to override bool AuthorizeCore(HttpContextBase httpContext)

11条回答
  •  说谎
    说谎 (楼主)
    2020-11-21 18:14

    The modern way is AuthenticationHandlers

    in startup.cs add

    services.AddAuthentication("BasicAuthentication").AddScheme("BasicAuthentication", null);
    
    public class BasicAuthenticationHandler : AuthenticationHandler
        {
            private readonly IUserService _userService;
    
            public BasicAuthenticationHandler(
                IOptionsMonitor options,
                ILoggerFactory logger,
                UrlEncoder encoder,
                ISystemClock clock,
                IUserService userService)
                : base(options, logger, encoder, clock)
            {
                _userService = userService;
            }
    
            protected override async Task HandleAuthenticateAsync()
            {
                if (!Request.Headers.ContainsKey("Authorization"))
                    return AuthenticateResult.Fail("Missing Authorization Header");
    
                User user = null;
                try
                {
                    var authHeader = AuthenticationHeaderValue.Parse(Request.Headers["Authorization"]);
                    var credentialBytes = Convert.FromBase64String(authHeader.Parameter);
                    var credentials = Encoding.UTF8.GetString(credentialBytes).Split(new[] { ':' }, 2);
                    var username = credentials[0];
                    var password = credentials[1];
                    user = await _userService.Authenticate(username, password);
                }
                catch
                {
                    return AuthenticateResult.Fail("Invalid Authorization Header");
                }
    
                if (user == null)
                    return AuthenticateResult.Fail("Invalid User-name or Password");
    
                var claims = new[] {
                    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                    new Claim(ClaimTypes.Name, user.Username),
                };
                var identity = new ClaimsIdentity(claims, Scheme.Name);
                var principal = new ClaimsPrincipal(identity);
                var ticket = new AuthenticationTicket(principal, Scheme.Name);
    
                return AuthenticateResult.Success(ticket);
            }
        }
    

    IUserService is a service that you make where you have user name and password. basically it returns a user class that you use to map your claims on.

    var claims = new[] {
                    new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
                    new Claim(ClaimTypes.Name, user.Username),
                }; 
    

    Then you can query these claims and her any data you mapped, ther are quite a few, have a look at ClaimTypes class

    you can use this in an extension method an get any of the mappings

    public int? GetUserId()
    {
       if (context.User.Identity.IsAuthenticated)
        {
           var id=context.User.FindFirst(ClaimTypes.NameIdentifier);
           if (!(id is null) && int.TryParse(id.Value, out var userId))
                return userId;
         }
          return new Nullable();
     }
    

    This new way, i think is better than the old way as shown here, both work

    public class BasicAuthenticationAttribute : AuthorizationFilterAttribute
    {
        public override void OnAuthorization(HttpActionContext actionContext)
        {
            if (actionContext.Request.Headers.Authorization != null)
            {
                var authToken = actionContext.Request.Headers.Authorization.Parameter;
                // decoding authToken we get decode value in 'Username:Password' format
                var decodeauthToken = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(authToken));
                // spliting decodeauthToken using ':'
                var arrUserNameandPassword = decodeauthToken.Split(':');
                // at 0th postion of array we get username and at 1st we get password
                if (IsAuthorizedUser(arrUserNameandPassword[0], arrUserNameandPassword[1]))
                {
                    // setting current principle
                    Thread.CurrentPrincipal = new GenericPrincipal(new GenericIdentity(arrUserNameandPassword[0]), null);
                }
                else
                {
                    actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
                }
            }
            else
            {
                actionContext.Response = actionContext.Request.CreateResponse(HttpStatusCode.Unauthorized);
            }
        }
    
        public static bool IsAuthorizedUser(string Username, string Password)
        {
            // In this method we can handle our database logic here...
            return Username.Equals("test") && Password == "test";
        }
    }
    

提交回复
热议问题