From 4b6460e7d564eebff7a79df475a702dbd3f009b9 Mon Sep 17 00:00:00 2001 From: crupest Date: Fri, 23 Apr 2021 19:06:11 +0800 Subject: feat: Fix #51. --- BackEnd/Timeline/Auth/MyAuthenticationHandler.cs | 63 ++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 3 deletions(-) (limited to 'BackEnd/Timeline/Auth/MyAuthenticationHandler.cs') diff --git a/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs b/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs index e4122c65..f1f71b20 100644 --- a/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs +++ b/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs @@ -1,13 +1,18 @@ using Microsoft.AspNetCore.Authentication; +using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using Microsoft.Net.Http.Headers; using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Security.Claims; using System.Text.Encodings.Web; +using System.Text.Json; using System.Threading.Tasks; +using Timeline.Models; +using Timeline.Models.Http; using Timeline.Services; using static Timeline.Resources.Authentication.AuthHandler; @@ -30,16 +35,33 @@ namespace Timeline.Auth public class MyAuthenticationHandler : AuthenticationHandler { + private const string TokenErrorCodeKey = "TokenErrorCode"; + + private static CommonResponse CreateChallengeResponseBody(int errorCode) + { + return new CommonResponse(errorCode, errorCode switch + { + ErrorCodes.Common.Token.TimeExpired => "The token is out of date and expired. Please create a new one.", + ErrorCodes.Common.Token.VersionExpired => "The token is of old version and expired. Please create a new one.", + ErrorCodes.Common.Token.BadFormat => "The token is of bad format. It might not be created by this server.", + ErrorCodes.Common.Token.UserNotExist => "The owner of the token does not exist. It might have been deleted.", + _ => "Unknown error." + }); + } + private readonly ILogger _logger; private readonly IUserTokenManager _userTokenManager; private readonly IUserPermissionService _userPermissionService; - public MyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserTokenManager userTokenManager, IUserPermissionService userPermissionService) + private readonly IOptionsMonitor _jsonOptions; + + public MyAuthenticationHandler(IOptionsMonitor options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserTokenManager userTokenManager, IUserPermissionService userPermissionService, IOptionsMonitor jsonOptions) : base(options, logger, encoder, clock) { _logger = logger.CreateLogger(); _userTokenManager = userTokenManager; _userPermissionService = userPermissionService; + _jsonOptions = jsonOptions; } // return null if no token is found @@ -49,7 +71,7 @@ namespace Timeline.Auth string header = Request.Headers[HeaderNames.Authorization]; if (!string.IsNullOrEmpty(header) && header.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase)) { - var token = header.Substring("Bearer ".Length).Trim(); + var token = header["Bearer ".Length..].Trim(); _logger.LogInformation(LogTokenFoundInHeader, token); return token; } @@ -98,8 +120,43 @@ namespace Timeline.Auth catch (Exception e) when (!(e is ArgumentException)) { _logger.LogInformation(e, LogTokenValidationFail); - return AuthenticateResult.Fail(e); + return AuthenticateResult.Fail(e, new AuthenticationProperties(new Dictionary() + { + [TokenErrorCodeKey] = (e switch + { + UserTokenTimeExpiredException => ErrorCodes.Common.Token.TimeExpired, + UserTokenVersionExpiredException => ErrorCodes.Common.Token.VersionExpired, + UserTokenBadFormatException => ErrorCodes.Common.Token.BadFormat, + UserTokenUserNotExistException => ErrorCodes.Common.Token.UserNotExist, + _ => ErrorCodes.Common.Token.Unknown + }).ToString(CultureInfo.InvariantCulture) + })); } } + + protected override async Task HandleChallengeAsync(AuthenticationProperties properties) + { + Response.StatusCode = 401; + + CommonResponse body; + + if (properties.Items.TryGetValue(TokenErrorCodeKey, out var tokenErrorCode)) + { + if (!int.TryParse(tokenErrorCode, out var errorCode)) + errorCode = ErrorCodes.Common.Token.Unknown; + body = CreateChallengeResponseBody(errorCode); + } + else + { + body = new CommonResponse(ErrorCodes.Common.Unauthorized, "You must use a token to authenticate."); + } + + + var bodyData = JsonSerializer.SerializeToUtf8Bytes(body, typeof(CommonResponse), _jsonOptions.CurrentValue.JsonSerializerOptions); + + Response.ContentType = MimeTypes.ApplicationJson; + Response.ContentLength = bodyData.Length; + await Response.Body.WriteAsync(bodyData); + } } } -- cgit v1.2.3