diff options
author | 杨宇千 <crupest@outlook.com> | 2019-10-31 00:56:46 +0800 |
---|---|---|
committer | 杨宇千 <crupest@outlook.com> | 2019-10-31 00:56:46 +0800 |
commit | d3a1bf5f2939049f11e77f91ad9ddea30d8acd64 (patch) | |
tree | 7d034bb824b50d892136c6f1225a15e8baa30741 /Timeline/Auth | |
parent | 006d799d2fe5f081c188f95a8590c4b75a93caae (diff) | |
download | timeline-d3a1bf5f2939049f11e77f91ad9ddea30d8acd64.tar.gz timeline-d3a1bf5f2939049f11e77f91ad9ddea30d8acd64.tar.bz2 timeline-d3a1bf5f2939049f11e77f91ad9ddea30d8acd64.zip |
Continue to construct feature and tests.
Diffstat (limited to 'Timeline/Auth')
-rw-r--r-- | Timeline/Auth/Attribute.cs | 21 | ||||
-rw-r--r-- | Timeline/Auth/MyAuthenticationHandler.cs | 99 | ||||
-rw-r--r-- | Timeline/Auth/PrincipalExtensions.cs | 13 |
3 files changed, 133 insertions, 0 deletions
diff --git a/Timeline/Auth/Attribute.cs b/Timeline/Auth/Attribute.cs new file mode 100644 index 00000000..86d0109b --- /dev/null +++ b/Timeline/Auth/Attribute.cs @@ -0,0 +1,21 @@ +using Microsoft.AspNetCore.Authorization;
+using Timeline.Entities;
+
+namespace Timeline.Auth
+{
+ public class AdminAuthorizeAttribute : AuthorizeAttribute
+ {
+ public AdminAuthorizeAttribute()
+ {
+ Roles = UserRoles.Admin;
+ }
+ }
+
+ public class UserAuthorizeAttribute : AuthorizeAttribute
+ {
+ public UserAuthorizeAttribute()
+ {
+ Roles = UserRoles.User;
+ }
+ }
+}
diff --git a/Timeline/Auth/MyAuthenticationHandler.cs b/Timeline/Auth/MyAuthenticationHandler.cs new file mode 100644 index 00000000..f5dcd697 --- /dev/null +++ b/Timeline/Auth/MyAuthenticationHandler.cs @@ -0,0 +1,99 @@ +using Microsoft.AspNetCore.Authentication;
+using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Options;
+using Microsoft.Net.Http.Headers;
+using System;
+using System.Linq;
+using System.Security.Claims;
+using System.Text.Encodings.Web;
+using System.Threading.Tasks;
+using Timeline.Models;
+using Timeline.Services;
+using static Timeline.Resources.Authentication.AuthHandler;
+
+namespace Timeline.Auth
+{
+ public static class AuthenticationConstants
+ {
+ public const string Scheme = "Bearer";
+ public const string DisplayName = "My Jwt Auth Scheme";
+ }
+
+ public class MyAuthenticationOptions : AuthenticationSchemeOptions
+ {
+ /// <summary>
+ /// The query param key to search for token. If null then query params are not searched for token. Default to <c>"token"</c>.
+ /// </summary>
+ public string TokenQueryParamKey { get; set; } = "token";
+ }
+
+ public class MyAuthenticationHandler : AuthenticationHandler<MyAuthenticationOptions>
+ {
+ private readonly ILogger<MyAuthenticationHandler> _logger;
+ private readonly IUserService _userService;
+
+ public MyAuthenticationHandler(IOptionsMonitor<MyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserService userService)
+ : base(options, logger, encoder, clock)
+ {
+ _logger = logger.CreateLogger<MyAuthenticationHandler>();
+ _userService = userService;
+ }
+
+ // return null if no token is found
+ private string? ExtractToken()
+ {
+ // check the authorization header
+ string header = Request.Headers[HeaderNames.Authorization];
+ if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.InvariantCultureIgnoreCase))
+ {
+ var token = header.Substring("Bearer ".Length).Trim();
+ _logger.LogInformation(LogTokenFoundInHeader, token);
+ return token;
+ }
+
+ // check the query params
+ var paramQueryKey = Options.TokenQueryParamKey;
+ if (!string.IsNullOrEmpty(paramQueryKey))
+ {
+ string token = Request.Query[paramQueryKey];
+ if (!string.IsNullOrEmpty(token))
+ {
+ _logger.LogInformation(LogTokenFoundInQuery, paramQueryKey, token);
+ return token;
+ }
+ }
+
+ // not found anywhere then return null
+ return null;
+ }
+
+ protected override async Task<AuthenticateResult> HandleAuthenticateAsync()
+ {
+ var token = ExtractToken();
+ if (string.IsNullOrEmpty(token))
+ {
+ _logger.LogInformation(LogTokenNotFound);
+ return AuthenticateResult.NoResult();
+ }
+
+ try
+ {
+ var userInfo = await _userService.VerifyToken(token);
+
+ var identity = new ClaimsIdentity(AuthenticationConstants.Scheme);
+ identity.AddClaim(new Claim(identity.NameClaimType, userInfo.Username, ClaimValueTypes.String));
+ identity.AddClaims(UserRoleConvert.ToArray(userInfo.Administrator).Select(role => new Claim(identity.RoleClaimType, role, ClaimValueTypes.String)));
+
+ var principal = new ClaimsPrincipal();
+ principal.AddIdentity(identity);
+
+ return AuthenticateResult.Success(new AuthenticationTicket(principal, AuthenticationConstants.Scheme));
+ }
+ catch (Exception e) when (!(e is ArgumentException))
+ {
+ _logger.LogInformation(e, LogTokenValidationFail);
+ return AuthenticateResult.Fail(e);
+ }
+ }
+ }
+}
diff --git a/Timeline/Auth/PrincipalExtensions.cs b/Timeline/Auth/PrincipalExtensions.cs new file mode 100644 index 00000000..ad7a887f --- /dev/null +++ b/Timeline/Auth/PrincipalExtensions.cs @@ -0,0 +1,13 @@ +using System.Security.Principal;
+using Timeline.Entities;
+
+namespace Timeline.Auth
+{
+ internal static class PrincipalExtensions
+ {
+ internal static bool IsAdministrator(this IPrincipal principal)
+ {
+ return principal.IsInRole(UserRoles.Admin);
+ }
+ }
+}
|