From eb50fc7ad1252d0e397e969e1a7eb33720150b00 Mon Sep 17 00:00:00 2001 From: 杨宇千 Date: Sat, 20 Jul 2019 19:01:35 +0800 Subject: Write a custom authenticate handler. --- Timeline/Authenticate/AuthHandler.cs | 96 ++++++++++++++++++++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 Timeline/Authenticate/AuthHandler.cs (limited to 'Timeline/Authenticate/AuthHandler.cs') diff --git a/Timeline/Authenticate/AuthHandler.cs b/Timeline/Authenticate/AuthHandler.cs new file mode 100644 index 00000000..71d8aeaa --- /dev/null +++ b/Timeline/Authenticate/AuthHandler.cs @@ -0,0 +1,96 @@ +using Microsoft.AspNetCore.Authentication; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using Microsoft.IdentityModel.Tokens; +using Microsoft.Net.Http.Headers; +using System; +using System.IdentityModel.Tokens.Jwt; +using System.Text.Encodings.Web; +using System.Threading.Tasks; + +namespace Timeline.Authenticate +{ + static class AuthConstants + { + public const string Scheme = "Bearer"; + public const string DisplayName = "My Jwt Auth Scheme"; + } + + class AuthOptions : AuthenticationSchemeOptions + { + /// + /// The query param key to search for token. If null then query params are not searched for token. Default to "token". + /// + public string TokenQueryParamKey { get; set; } = "token"; + + public TokenValidationParameters TokenValidationParameters { get; + set; } + = new TokenValidationParameters(); + } + + class AuthHandler : AuthenticationHandler + { + private readonly ILogger _logger; + + public AuthHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock) + : base(options, logger, encoder, clock) + { + _logger = logger.CreateLogger(); + } + + // 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.OrdinalIgnoreCase)) + { + var token = header.Substring("Bearer ".Length).Trim(); + _logger.LogInformation("Token is found in authorization header. Token is {} .", 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("Token is found in query param with key \"{}\". Token is {} .", paramQueryKey, token); + return token; + } + } + + // not found anywhere then return null + return null; + } + + protected override async Task HandleAuthenticateAsync() + { + var token = ExtractToken(); + if (string.IsNullOrEmpty(token)) + { + _logger.LogInformation("No jwt token is found."); + return AuthenticateResult.NoResult(); + } + + var handler = new JwtSecurityTokenHandler(); + try + { + var principal = handler.ValidateToken(token, Options.TokenValidationParameters, out var validatedToken); + return AuthenticateResult.Success(new AuthenticationTicket(principal, AuthConstants.Scheme)); + } + catch (SecurityTokenException e) + { + _logger.LogInformation(e, "A jwt token validation failed."); + return AuthenticateResult.Fail(e); + } + catch (Exception e) + { + _logger.LogError(e, "Arguments passed to the JwtSecurityTokenHandler.ValidateToken are bad."); + throw e; + } + } + } +} -- cgit v1.2.3