在 .net 核心 web api 中存储 JWT 令牌的位置?

Posted

技术标签:

【中文标题】在 .net 核心 web api 中存储 JWT 令牌的位置?【英文标题】:Where to store JWT Token in .net core web api? 【发布时间】:2019-04-26 14:41:37 【问题描述】:

我正在使用 web api 来访问数据,并且我想对 web api 进行身份验证和授权。为此,我正在使用 JWT 令牌身份验证。但我不知道应该在哪里存储访问令牌?

我想做什么?

1)登录后存储令牌

2)如果用户想访问web api的任何方法,检查token对该用户是否有效,如果有效则授予访问权限。

我知道两种方法

1) 使用 cookie

2)sql server 数据库

从上面存储令牌的更好方法是哪一种?

【问题讨论】:

您能否进一步解释您的用例。您是否想在您的 webapi 上强制执行身份验证,以便您的调用者在调用您的控制器和操作之前需要进行身份验证,或者您的 webapi 是否正在调用另一个需要对您的调用进行身份验证的系统?如果您正在尝试实现先前的选项,则无需担心如果您已完成自定义中间件,除非您正在考虑拆分应用程序的多个实例并且您需要共享会话(不知道为什么要使用会议虽然) 但是,如果您询问如何在成功验证后将令牌交付给调用者,您有两种选择。使用标准 owin 中间件使用承载来处理身份验证,然后您可以在响应中返回 jwt(风险在于您的最终客户端以保护令牌)或配置中间件以使用 cookie 身份验证并仅返回带有标头 Set 的 cookie cookie 然后您的客户端可以保存 cookie 而不必担心任何其他应用程序能够访问其信息 你认为为什么需要将 jwt 存储在任何地方? 通过比较token来验证用户是否有效 【参考方案1】:

我不熟悉将用户令牌存储在后端应用程序中,我将快速检查它是如何工作的不需要在你身边存放任何东西。

如果您使用 cookie,那么您只需要配置中间件来验证 cookie 的有效性,如果它出现在用户/消费者的标头中,如果不可用或已过期或无法解析,您只需拒绝请求和用户甚至不会点击任何受保护的控制器和操作。这是一个非常简化的 cookie 方法。(我仍在使用它进行开发,尚未在生产中进行测试,但现在使用 JS 客户端和 Postman 在本地工作得很好)

services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
       .AddCookie(options =>
       
           options.Cookie.Name = "yourCookieName";
           options.Cookie.SameSite = SameSiteMode.None;//its recommended but you can set it to any of the other 3 depending on your reqirements
           options.Events = new Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationEvents
           
               OnRedirectToLogin = redirectContext =>//this will be called if an unauthorized connection comes and you can do something similar to this or more
               
                   redirectContext.HttpContext.Response.StatusCode = 401;
                   return Task.CompletedTask;
               ,
               OnValidatePrincipal = context => //if a call comes with a valid cookie, you can use this to do validations. in there you have access to the request and http context so you should have enough to work with
               
                   var userPrincipal = context.Principal;//I'm not doing anything with this right now but I could for instance validate if the user has the right privileges like claims etc
                   return Task.CompletedTask;
               
           ;
       );

显然这将被放置或调用在您启动的 ConfigureServices 方法中以注册身份验证

然后在 Startup 的 Configure 方法中,您可以像这样连接身份验证

app.UseAuthentication();

之前

app.UseMvc()

【讨论】:

【参考方案2】:

或者,如果您只是想使用 JWT 进行身份验证,则实现会略有不同

services.AddAuthentication(options =>

    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
).AddJwtBearer(options =>

    options.Events = new JwtBearerEvents
    
        OnTokenValidated = context =>
        
            var user = context.Principal.Identity.Name;
            //Grab the http context user and validate the things you need to
            //if you are not satisfied with the validation fail the request using the below commented code
            //context.Fail("Unauthorized");
            
            //otherwise succeed the request
            return Task.CompletedTask;
        
    ;
    options.RequireHttpsMetadata = false;
    options.SaveToken = true;
    options.TokenValidationParameters = new TokenValidationParameters
    
        ValidateIssuerSigningKey = true,
        IssuerSigningKey = new SymmetricSecurityKey("MyVeryStrongKeyHiddenFromAnyone"),
        ValidateIssuer = false,
        ValidateAudience = false

    ;
);

在使用 MVC 之前仍然应用使用身份验证。

[请注意,这些是非常简化的示例,您可能需要进一步加强安全性并实施最佳实践,例如使用强密钥、可能从环境中加载配置等]

那么实际的身份验证操作,比如在 AuthenticationController 中可能类似于

[Route("api/[controller]")]
[Authorize]
public class AuthenticationController : Controller

    [HttpPost("authenticate")]
    [AllowAnonymous]
    public async Task<IActionResult> AuthenticateAsync([FromBody]LoginRequest loginRequest)
    
        //LoginRequest may have any number of fields expected .i.e. username and password

        //validate user credentials and if they fail return
        //return Unauthorized();

        var claimsIdentity = new ClaimsIdentity(new Claim[]
           
            //add relevant user claims if any
           , "Cookies");

        var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);
        await Request.HttpContext.SignInAsync("Cookies", claimsPrincipal);
        return Ok();
    

在这种情况下,我使用 cookie,因此我使用 Set Cookie 返回 HTTP 结果。如果我使用的是 JWT,我会返回类似

[HttpPost("authenticate")]
public IActionResult Authenticate([FromBody]LoginRequest loginRequest)

    //validate user credentials and if they validation failed return a similar response to below
    //return NotFound();

    var tokenHandler = new JwtSecurityTokenHandler();
    var key = Encoding.ASCII.GetBytes("MySecurelyInjectedAsymKey");
    var tokenDescriptor = new SecurityTokenDescriptor
    
        Subject = new ClaimsIdentity(new Claim[]
        
            //add my users claims etc
        ),
        Expires = DateTime.UtcNow.AddDays(1),//configure your token lifespan and needed
        SigningCredentials = new SigningCredentials(new SymmetricSecurityKey("MyVerySecureSecreteKey"), SecurityAlgorithms.HmacSha256Signature),
        Issuer = "YourOrganizationOrUniqueKey",
        IssuedAt = DateTime.UtcNow
    ;

    var token = tokenHandler.CreateToken(tokenDescriptor);
    var tokenString = tokenHandler.WriteToken(token);
    var cookieOptions = new CookieOptions();
    cookieOptions.Expires = DateTimeOffset.UtcNow.AddHours(4);//you can set this to a suitable timeframe for your situation 
    cookieOptions.Domain = Request.Host.Value;
    cookieOptions.Path = "/";
    Response.Cookies.Append("jwt", tokenString, cookieOptions);
    return Ok();

【讨论】:

感谢您的解决方案,但这里的 IUserDomain 是什么...? 没问题,不用担心,这些基本上只是服务编排,有助于执行某些操作,例如访问数据库以验证用户凭据或调用内部身份验证系统。但是您是否掌握了不需要使用数据库来存储令牌的基本知识

以上是关于在 .net 核心 web api 中存储 JWT 令牌的位置?的主要内容,如果未能解决你的问题,请参考以下文章

使用 JWT 令牌保护 asp.net 核心 Web api 时如何从 Azure AD 获取用户

text 使用ASP.NET Core 2 Web API,Angular 5,.NET核心身份和Facebook登录进行JWT身份验证

JWT 和 asp.net(核心)Web 应用程序

AzureAD 的 JWT 在 .NET 核心 API 中提供 403 Forbidden

使用 .net 核心 Web API 对 .net 控制台应用程序进行身份验证

JWT 不记名令牌授权应用于 .NET Core 中的现有 MVC Web 应用程序