diff --git a/src/Server/Controllers/AuthenticationController.cs b/src/Server/Controllers/AuthenticationController.cs index 994ddc1..0c2bc5c 100755 --- a/src/Server/Controllers/AuthenticationController.cs +++ b/src/Server/Controllers/AuthenticationController.cs @@ -34,19 +34,9 @@ namespace BoredCareers.Controllers { test.CurrentPasswordAttempts = 0; await _databaseService.SetAccount(test); - List claims = new List() { - new Claim("ID", test.ID.ToString()), - new Claim(ClaimTypes.NameIdentifier, test.ID.ToString()) - }; + string jwt = BoredCareersJWT.GenereateJWTToken(test.ID, StayLoggedIn); + BoredCareersJWT.SignIn(Response, StayLoggedIn, jwt); - await HttpContext.SignInAsync( - CookieAuthenticationDefaults.AuthenticationScheme, - new ClaimsPrincipal(new ClaimsIdentity(claims, "Auth")), - new AuthenticationProperties { - ExpiresUtc = DateTime.UtcNow.AddYears(30), // Add 30 years with sliding on - IsPersistent = StayLoggedIn, // Is set from the StayLoggedIn - } - ); return Ok(test); } else { test.CurrentPasswordAttempts += 1; @@ -151,9 +141,9 @@ namespace BoredCareers.Controllers { [Route("logout")] [HttpPost] - public async Task Logout() { + public ActionResult Logout() { if (isLoggedIn()) { - await HttpContext.SignOutAsync(); + BoredCareersJWT.SignOut(Response); return Ok(); } return NotFound(); diff --git a/src/Server/Program.cs b/src/Server/Program.cs index d4396af..fdc9bc3 100755 --- a/src/Server/Program.cs +++ b/src/Server/Program.cs @@ -5,6 +5,11 @@ using BoredCareers.Services.DatabaseService; using System.Threading.RateLimiting; using Stripe; using System.Security.Claims; +using Microsoft.AspNetCore.Authentication.JwtBearer; +using Microsoft.IdentityModel.Tokens; +using Org.BouncyCastle.Bcpg.Sig; +using System.Text; +using System.IdentityModel.Tokens.Jwt; var builder = WebApplication.CreateBuilder(args); @@ -81,15 +86,40 @@ if (IPayment._PaymentType == PaymentType.StripeIntent) { } // Authentication Service -builder.Services.AddAuthentication( options => { - options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; -} ).AddCookie(options => { - options.Cookie.HttpOnly = true; - options.Cookie.SecurePolicy = CookieSecurePolicy.Always; - options.Cookie.SameSite = SameSiteMode.Strict; - options.LoginPath = "/account/login"; - options.LogoutPath = "/account/logout"; - options.SlidingExpiration = true; +builder.Services.AddAuthentication(options => { + options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; + options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; +}).AddJwtBearer(options => { + options.TokenValidationParameters = new TokenValidationParameters { + ValidateIssuer = true, + ValidateAudience = true, + ValidateLifetime = true, + ValidateIssuerSigningKey = true, + ValidIssuer = "your-app", + ValidAudience = "your-app", + IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("secret-key")), + ClockSkew = TimeSpan.FromMinutes(1) + }; + options.Events = new JwtBearerEvents { + OnMessageReceived = context => { + context.Token = context.Request.Cookies["access_token"]; + return Task.CompletedTask; + }, + OnTokenValidated = context => { + var jwtToken = context.SecurityToken as JwtSecurityToken; + if (jwtToken != null) { + var exp = jwtToken.ValidTo; + var now = DateTime.UtcNow; + if ((exp - now) < TimeSpan.FromMinutes(5)) { + int accountID = Convert.ToInt32(context.Principal?.FindFirst(ClaimTypes.NameIdentifier)?.Value); + bool isPersistent = bool.Parse(context.Principal?.FindFirst(ClaimTypes.IsPersistent)?.Value); + var newJWT = BoredCareersJWT.GenereateJWTToken(accountID, isPersistent); + BoredCareersJWT.SignIn(context.HttpContext.Response, isPersistent, newJWT); + } + } + return Task.CompletedTask; + } + }; }); builder.Services.AddCors(o => o.AddDefaultPolicy(builder => { diff --git a/src/Server/Server.csproj b/src/Server/Server.csproj index 621ce3d..c14307e 100755 --- a/src/Server/Server.csproj +++ b/src/Server/Server.csproj @@ -11,6 +11,7 @@ + diff --git a/src/Server/Services/jwt.cs b/src/Server/Services/jwt.cs new file mode 100644 index 0000000..4d1a03c --- /dev/null +++ b/src/Server/Services/jwt.cs @@ -0,0 +1,54 @@ + + +using System.IdentityModel.Tokens.Jwt; +using System.Security.Claims; +using System.Text; +using Microsoft.IdentityModel.Tokens; + +namespace BoredCareers.Services { + public class BoredCareersJWT { + public static string GenereateJWTToken(int accountID, bool StayLoggedIn) { + var tokenHandler = new JwtSecurityTokenHandler(); + var key = Encoding.UTF8.GetBytes("your-super-secret-key"); + + var tokenDiscriptor = new SecurityTokenDescriptor { + Subject = new ClaimsIdentity(new[] { + new Claim(ClaimTypes.NameIdentifier, accountID.ToString()), + new Claim(ClaimTypes.IsPersistent, StayLoggedIn.ToString()) + }), + Expires = DateTime.UtcNow.AddMinutes(15), + IssuedAt = DateTime.UtcNow, + SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.RsaSha512), + Audience = "your-app", + Issuer = "your-app" + }; + + var token = tokenHandler.CreateToken(tokenDiscriptor); + return tokenHandler.WriteToken(token); + } + + public static void SignIn(HttpResponse Response, bool StayLoggedIn, string jwt) { + if (StayLoggedIn) { + // Stay logged in cookie + Response.Cookies.Append("access_token", jwt, new CookieOptions { + Secure = true, + HttpOnly = true, + SameSite = SameSiteMode.Strict, + Expires = DateTime.UtcNow.AddMinutes(15) + }); + } + else { + // Session cookie + Response.Cookies.Append("access_token", jwt, new CookieOptions { + Secure = true, + HttpOnly = true, + SameSite = SameSiteMode.Strict, + }); + } + } + + public static void SignOut(HttpResponse Response) { + Response.Cookies.Delete("access_token"); + } + } +} \ No newline at end of file