aboutsummaryrefslogtreecommitdiff
path: root/BackEnd/Timeline/Auth/MyAuthenticationHandler.cs
diff options
context:
space:
mode:
Diffstat (limited to 'BackEnd/Timeline/Auth/MyAuthenticationHandler.cs')
-rw-r--r--BackEnd/Timeline/Auth/MyAuthenticationHandler.cs63
1 files changed, 60 insertions, 3 deletions
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<MyAuthenticationOptions>
{
+ 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<MyAuthenticationHandler> _logger;
private readonly IUserTokenManager _userTokenManager;
private readonly IUserPermissionService _userPermissionService;
- public MyAuthenticationHandler(IOptionsMonitor<MyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserTokenManager userTokenManager, IUserPermissionService userPermissionService)
+ private readonly IOptionsMonitor<JsonOptions> _jsonOptions;
+
+ public MyAuthenticationHandler(IOptionsMonitor<MyAuthenticationOptions> options, ILoggerFactory logger, UrlEncoder encoder, ISystemClock clock, IUserTokenManager userTokenManager, IUserPermissionService userPermissionService, IOptionsMonitor<JsonOptions> jsonOptions)
: base(options, logger, encoder, clock)
{
_logger = logger.CreateLogger<MyAuthenticationHandler>();
_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<string, string?>()
+ {
+ [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);
+ }
}
}