gpt4 book ai didi

c# - ASP.NET Core 3.1 - 如何在经过身份验证后持久保存 JWT token

转载 作者:行者123 更新时间:2023-12-03 17:00:56 26 4
gpt4 key购买 nike

我一直在尝试让 JWT 身份验证正常工作,但尚不清楚这需要如何完成,以及在 ASP.NET Core 3.1 中执行此操作的最佳方法是什么。

我正在使用基于 Cookie 的身份验证,我假设它与 session ID 相关联, session ID 与正在运行的服务器实例相关联。如果我想使用具有不同 IP 地址和端口的多个服务器,我假设 cookie 将不再起作用,因此需要其他可以跨系统验证的东西。

我一直在关注各种 Web 示例,但不清楚一旦用户“经过身份验证” - 登录后,我拥有 JWT token 之后该怎么做。用户登录后,他们可以通过以下方式访问系统的任何部分:html 链接( 菜单 )。

如何在所有后续请求中传递 token ?

在用户通过身份验证并将 token 存储在浏览器 sessionStore 或 localStorage 或 Cookie 中后,我是否将用户重定向到欢迎页面?处理这个问题的最佳方法是什么。

options.success = function (obj) {
sessionStorage.setItem("token", obj.token);
sessionStorage.setItem("userName",$("#userName").val());
}

HTTP header

Would the Authorization HTTP Header variable work and would this be sent around in all subsequent requests by the browser, acting as the HTTP client. How long does this HTTP header last, is it lost once the TCP socket is closed? How do I set this HTTP Header Variable in ASP.NET Core 3.1? Would the server then use this Header to validate the token, and also pass it on again for use in subsequent requests?



目前我有这个,一旦用户通过身份验证,它就会在正文中返回 token :
        var claims = await GetClaims(user);
var token = GenerateSecurityToken(claims);

return Ok(new { Token = token })

AJAX 调用

我有几个表单和几个 AJAX 调用,如何将其作为手动方法实现似乎相当乏味。

Is there a way to get the JWT token from a hidden form variable similar to the AntiForgery token @Html.AntiForgeryToken() as used in all my Ajax calls?



jQuery 使用隐藏的表单变量:
request = $.ajax({
async: true,
url: url,
type: "POST",
contentType: "application/json; charset=utf-8",
dataType: "json",
headers: {
RequestVerificationToken:
$('input:hidden[name="__RequestVerificationToken"]').val()
},
WHAT DO I ADD FOR JWT ?
data: JSON.stringify(data)
}).done(function() {
completion();
}).fail(function() {
// fail
});

HTML 表单

我有 Razor Pages 并有一些表单,然后 POST 回 Controller 。如何包含 token ?

Controller

使用 JWT 时是否还有其他需要执行的操作
除了我的 Startup.cs 中还有什么?我知道我需要处理 token 刷新,但我会离开一个单独的问题。

菜单中的链接 - HTTP GET

我可以通过将 token 添加到 URL 的末尾来操纵呈现给用户的菜单/链接,但是应该如何完成呢?

最佳答案

经过大量阅读后,我找到了一些答案以及可行的解决方案。

HTTP header
获得 token 后,需要保留 token 才能访问系统。使用 HTTP header 存储 token 不会持续存在,因为 HTTP 协议(protocol) 1.0 和 1.1 和 1.2 将在某个时候关闭 TCP 套接字以及它所具有的状态,即 token 。不适合不控制 Http 连接的 WebClients,但可以用于移动开发、Android 或 IOS,如果您可以控制 HttpHeaders。

本地存储
您可以使用浏览器 localStoragesessionStorage ,但是这些存在一些安全风险,JavaScript 可以读取这些值 - XSS攻击。

cookies
另一种选择是将 token 存储在 Cookie 中; cookie 将与每个 http 请求一起传递,客户端不需要为此发生任何特殊情况。这种方法不易受到 XSS 攻击。但容易出现CSRF .但是 CORS 再次可以帮助解决这个问题。

最好将 Cookie 设置为 HttpOnly,这样 cookie 将仅通过 HTTPS 传递。 Read more here

这是我根据我发现的一篇文章的实现
here

启动.cs 配置服务...

        // openssl rand -hex 16 => 32 bytes when read
var jwt_key = Configuration.GetSection("JwtOption:IssuerSigningKey").Value;
var signingKey = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(jwt_key));
var tokenValidationParameters = new TokenValidationParameters
{
// The signing key must match!
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,

// Validate the JWT Issuer (iss) claim
ValidateIssuer = true,
ValidIssuer = "some uri",

// Validate the JWT Audience (aud) claim
ValidateAudience = true,
ValidAudience = "the web",

// Validate the token expiry
ValidateLifetime = true,

// If you want to allow a certain amount of clock drift, set that here:
ClockSkew = TimeSpan.Zero
};

services.AddSingleton(tokenValidationParameters);

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme).AddCookie(options =>
{
int minute = 60;
int hour = minute * 60;
int day = hour * 24;
int week = day * 7;
int year = 365 * day;

options.LoginPath = "/auth/login";
options.AccessDeniedPath = "/auth/accessdenied";
options.Cookie.IsEssential = true;
options.SlidingExpiration = true;
options.ExpireTimeSpan = TimeSpan.FromSeconds(day/2);

options.Cookie.Name = "access_token";

options.TicketDataFormat = new CustomJwtDataFormat(
SecurityAlgorithms.HmacSha256,
tokenValidationParameters);
});

自定义JwtDataFormat 这将验证我们的 token 。
public class CustomJwtDataFormat :ISecureDataFormat<AuthenticationTicket>
{
private readonly string algorithm;
private readonly TokenValidationParameters validationParameters;

public CustomJwtDataFormat(string algorithm, TokenValidationParameters validationParameters)
{
this.algorithm = algorithm;
this.validationParameters = validationParameters;
}

public AuthenticationTicket Unprotect(string protectedText)
=> Unprotect(protectedText, null);

public AuthenticationTicket Unprotect(string protectedText, string purpose)
{
var handler = new JwtSecurityTokenHandler();
ClaimsPrincipal principal = null;
SecurityToken validToken = null;

try
{
principal = handler.ValidateToken(protectedText, this.validationParameters, out validToken);

var validJwt = validToken as JwtSecurityToken;

if (validJwt == null)
{
throw new ArgumentException("Invalid JWT");
}

if (!validJwt.Header.Alg.Equals(algorithm, StringComparison.Ordinal))
{
throw new ArgumentException($"Algorithm must be '{algorithm}'");
}

// Additional custom validation of JWT claims here (if any)
}
catch (SecurityTokenValidationException e)
{
System.Console.WriteLine(e);
return null;
}
catch (ArgumentException e)
{
System.Console.WriteLine(e);
return null;
}

// Validation passed. Return a valid AuthenticationTicket:
return new AuthenticationTicket(principal, new AuthenticationProperties(), "Cookie");
}

// This ISecureDataFormat implementation is decode-only
public string Protect(AuthenticationTicket data)
{
throw new NotImplementedException();
}

public string Protect(AuthenticationTicket data, string purpose)
{
throw new NotImplementedException();
}
}

登录 Controller 验证用户名和密码后,调用 SignInUser
    private string GenerateSecurityToken(List<Claim> claims)
{
var tokenHandler = new JwtSecurityTokenHandler();
var expire = System.DateTime.UtcNow.AddMinutes(userService.GetJwtExpireDate());
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = expire,
SigningCredentials = new SigningCredentials(tokenValidationParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256Signature),
Audience = tokenValidationParameters.ValidAudience,
Issuer = tokenValidationParameters.ValidIssuer
};

var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}

private async Task<List<Claim>> GetClaims(UserModel user) {
var claims = new List<Claim>
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.Email),
new Claim(ClaimTypes.Email, user.Email),
};

// add roles
var roleList = await userService.UserRoles(user.Email);
foreach (var role in roleList)
{
var claim = new Claim(ClaimTypes.Role, role.Role);
claims.Add(claim);
}

return claims;
}

private async Task<IActionResult> SignInUser(UserModel user, bool rememberMe)
{
var claims = await GetClaims(user);
var token = GenerateSecurityToken(claims);

// return Ok(new { Token = token });
// HttpContext.Request.Headers.Add("Authorization", $"Bearer {token}");

// HttpContext.Response.Cookies.Append(
HttpContext.Response.Cookies.Append("access_token", token, new CookieOptions { HttpOnly = true, Secure = true });
return RedirectToAction("Index", "Home", new { area = "" });
}

关于c# - ASP.NET Core 3.1 - 如何在经过身份验证后持久保存 JWT token ,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60923132/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com