如何在OWIN授权代码中获取生成的Bearer Token并存入数据库?
解决OWIN Bearer Token在代码中获取并存储到数据库的问题
我完全懂你遇到的困扰:你已经用OWIN搭好了Bearer Token认证,登录接口能正常返回Token,但想在后端代码里直接拿到这个Token存数据库,不用额外调接口,可在GrantResourceOwnerCredentials里的AuthenticationTicket里根本找不到生成的Token值。
为什么在GrantResourceOwnerCredentials里拿不到Token?
其实逻辑很清晰:GrantResourceOwnerCredentials的职责只是验证用户身份并生成认证票据(AuthenticationTicket),最终的access_token是在这个方法执行完成后,由OWIN的OAuth中间件基于这个票据生成的(不管是默认的加密Token还是JWT格式)。所以在这个方法里,Token还没被生成,自然找不到。
两种可行的解决办法
方法一:重写TokenEndpoint方法拦截Token
这是最直接的方案,TokenEndpoint方法是在Token生成完成后、返回给客户端之前执行的,在这里你可以轻松拿到最终的access_token,然后存入数据库。
把这个方法加到你现有的OAuthAuthorizationServerProvider实现里:
public override Task TokenEndpoint(OAuthTokenEndpointContext context) { // 拿到已经生成的access_token var accessToken = context.AccessToken; // 从Identity里获取用户标识(比如你之前加的UserID Claim) var userId = context.Identity.FindFirst("UserID")?.Value; // 这里调用你的业务逻辑,把Token和用户信息存入数据库 // 示例: var tokenService = new TokenService(); tokenService.SaveUserToken(userId, accessToken, context.Properties.ExpiresUtc); // 继续执行默认逻辑,返回Token给客户端 return base.TokenEndpoint(context); }
方法二:自定义Token生成器(适合需要完全控制Token的场景)
如果需要更深度的自定义(比如自己生成JWT Token),可以实现ISecureDataFormat<AuthenticationTicket>接口,替换默认的Token格式。这样在生成Token的过程中你就能直接拿到Token值并存库。
示例代码大概是这样:
public class CustomJwtFormat : ISecureDataFormat<AuthenticationTicket> { private readonly string _issuer; public CustomJwtFormat(string issuer) { _issuer = issuer; } public string Protect(AuthenticationTicket data) { if (data == null) throw new ArgumentNullException(nameof(data)); // 自定义生成JWT Token的逻辑 var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的密钥")); var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256); var token = new JwtSecurityToken( issuer: _issuer, audience: _issuer, claims: data.Identity.Claims, expires: data.Properties.ExpiresUtc?.UtcDateTime, signingCredentials: creds); var tokenString = new JwtSecurityTokenHandler().WriteToken(token); // 在这里把tokenString存入数据库 var userId = data.Identity.FindFirst("UserID")?.Value; var tokenService = new TokenService(); tokenService.SaveUserToken(userId, tokenString, data.Properties.ExpiresUtc); return tokenString; } public AuthenticationTicket Unprotect(string protectedText) { // 实现Token解析逻辑,验证时会用到 throw new NotImplementedException(); } }
然后在Startup里配置OAuthOptions时指定这个自定义格式:
Startup.OAuthOptions.AccessTokenFormat = new CustomJwtFormat("你的Issuer");
注意事项
- 记得存储Token的时候同时保存过期时间(
context.Properties.ExpiresUtc),后续可以定时清理过期的无效Token,避免数据库冗余。 - 如果用的是默认的OWIN Token(非JWT),它是加密后的字符串,存入数据库后如果需要验证的话,还需要用对应的解密逻辑,但一般来说存储只是做记录,不需要解密。
内容的提问来源于stack exchange,提问作者devedv




