You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

如何在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

火山引擎 最新活动