Change to JWT inside Secure Cookie Auth
This commit is contained in:
@@ -34,19 +34,9 @@ namespace BoredCareers.Controllers {
|
||||
test.CurrentPasswordAttempts = 0;
|
||||
await _databaseService.SetAccount(test);
|
||||
|
||||
List<Claim> claims = new List<Claim>() {
|
||||
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<ActionResult> Logout() {
|
||||
public ActionResult Logout() {
|
||||
if (isLoggedIn()) {
|
||||
await HttpContext.SignOutAsync();
|
||||
BoredCareersJWT.SignOut(Response);
|
||||
return Ok();
|
||||
}
|
||||
return NotFound();
|
||||
|
||||
+39
-9
@@ -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 => {
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.Server" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="9.0.3" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.WebApiCompatShim" Version="2.3.0" />
|
||||
<PackageReference Include="MySql.Data" Version="9.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user