You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Owin Token实现跨服务MVC与WebAPI身份认证问题求助

问题分析与解决方案

你遇到的核心问题是:直接把MVC的.AspNet.ApplicationCookie值当作Bearer Token发送给WebAPI是行不通的。这个Cookie里存储的是Owin Cookie认证模块加密后的Cookie认证票据(Cookie Authentication Ticket),而WebAPI配置的OAuthBearerAuthenticationMiddleware是用来解析标准OAuth2 Bearer Token(比如JWT格式)的,两者的格式、加密逻辑完全不同——哪怕两边MachineKey一致,Bearer中间件也无法识别Cookie票据的格式。

下面给你三个不同方向的解决方案,你可以根据自己的需求选择:


方案1:让WebAPI直接支持Cookie认证(最简单的无缝方案)

既然MVC和WebAPI已经配置了相同的MachineKey,你可以直接在WebAPI中启用Cookie认证中间件,这样MVC的认证Cookie就能被WebAPI直接识别,不需要手动处理Bearer请求头。如果你的核心需求是“无缝验证已认证请求”,这是最省事的选择:

修改WebAPI的启动配置代码:

// 先添加Cookie认证,参数必须和MVC完全一致
app.UseCookieAuthentication(new CookieAuthenticationOptions() 
{ 
    AuthenticationType = "你的Auth_type值", // 要和MVC里的Auth_type完全匹配
    CookieName = ".AspNet.ApplicationCookie", // 和MVC的Cookie名称保持一致
    CookieSecure = CookieSecureOption.Never,
    CookieHttpOnly = false,
    AuthenticationMode = AuthenticationMode.Active // 主动验证Cookie中的身份信息
});

// 保留原有的Bearer认证,兼容两种认证方式
var OAuthOptions = new OAuthBearerAuthenticationOptions 
{ 
    AuthenticationMode = Microsoft.Owin.Security.AuthenticationMode.Passive, 
    AuthenticationType = OAuthDefaults.AuthenticationType, 
}; 
app.UseOAuthBearerAuthentication(OAuthOptions);

配置完成后,当MVC的前端带着认证Cookie请求WebAPI时,API会自动识别并验证身份,不需要额外修改前端代码。


方案2:生成标准JWT Token传给WebAPI(规范的跨服务认证方案)

如果必须使用Bearer请求头的方式,推荐从MVC的已认证用户Claims生成标准的JWT Token,然后WebAPI用JWT认证中间件验证。这种方式更符合现代跨服务认证的规范,也更容易扩展到其他服务:

步骤1:在MVC项目中添加JWT生成逻辑

首先安装System.IdentityModel.Tokens.Jwt包,然后在登录成功后生成JWT并传递给前端:

// 登录成功后(比如SignIn之后)
var claimsIdentity = User.Identity as ClaimsIdentity;
// 生成JWT需要的密钥,两边(MVC和API)必须一致
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的共享密钥,比如一个随机的长字符串"));
var signingCredentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

// 构建JWT Token
var jwtToken = new JwtSecurityToken(
    issuer: "https://your-mvc-domain.com", // MVC网站的标识
    audience: "https://your-api-domain.com", // WebAPI的标识
    claims: claimsIdentity.Claims, // 携带用户的Claims信息
    expires: DateTime.Now.AddHours(1), // Token过期时间
    signingCredentials: signingCredentials
);

// 把JWT转为字符串,存在Cookie或者localStorage中
var tokenString = new JwtSecurityTokenHandler().WriteToken(jwtToken);
Response.Cookies.Append("JwtToken", tokenString, new CookieOptions { HttpOnly = false, Secure = false });

步骤2:修改WebAPI的启动配置,启用JWT认证

同样安装System.IdentityModel.Tokens.Jwt包,然后修改Startup代码:

app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
    TokenValidationParameters = new TokenValidationParameters
    {
        ValidateIssuer = true,
        ValidateAudience = true,
        ValidateLifetime = true,
        ValidateIssuerSigningKey = true,
        ValidIssuer = "https://your-mvc-domain.com", // 和MVC生成时的issuer一致
        ValidAudience = "https://your-api-domain.com", // 和MVC生成时的audience一致
        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("你的共享密钥,和MVC里的一样"))
    }
});

步骤3:前端修改Bearer头为JWT Token

// 取刚才生成的JWT Token,而不是Cookie值
var token = getCookie("JwtToken"); 
$.ajax({
    type: "GET",
    beforeSend: function (request) {
        request.setRequestHeader("Authorization", "Bearer " + token);
    },
    url: "http://localhost:1231/authapi/api/values/get?id=1",
    success: function (msg) { alert("Success" + msg) },
    error: function (d) { debugger; alert("Error" + d.responseText) }
});

方案3:自定义Bearer中间件解析Cookie票据(适配现有Cookie逻辑)

如果不想改动现有的Cookie认证流程,又要坚持使用Bearer头,可以自定义一个Bearer认证提供器,让WebAPI能够解密MVC的Cookie票据:

步骤1:在WebAPI中自定义Bearer认证提供器

public class CookieTicketBearerAuthenticationProvider : OAuthBearerAuthenticationProvider
{
    private readonly string _authenticationType;
    private readonly MachineKeyProtector _protector;

    public CookieTicketBearerAuthenticationProvider(string authenticationType)
    {
        _authenticationType = authenticationType;
        // 使用和MVC相同的MachineKey解密,参数要和Owin Cookie内部的保护参数一致
        _protector = new MachineKeyProtector(
            "Microsoft.Owin.Security.Cookies.CookieAuthenticationMiddleware",
            authenticationType,
            "v1");
    }

    public override Task RequestToken(OAuthRequestTokenContext context)
    {
        // 从Authorization头获取Bearer Token(也就是MVC的Cookie值)
        var token = context.Request.Headers.Get("Authorization")?.Replace("Bearer ", "");
        if (!string.IsNullOrEmpty(token))
        {
            try
            {
                // 解密Cookie中的认证票据
                var decodedTicket = WebUtility.UrlDecode(token);
                var ticketBytes = Convert.FromBase64String(decodedTicket);
                var unprotectedBytes = _protector.Unprotect(ticketBytes);
                var authenticationTicket = TicketSerializer.Default.Deserialize(unprotectedBytes);
                
                // 将解密后的身份信息加入Owin上下文
                context.OwinContext.Authentication.SignIn(authenticationTicket.Identity);
            }
            catch
            {
                // 解密失败时忽略,交给其他认证中间件处理
            }
        }
        return Task.FromResult<object>(null);
    }
}

// 复制Owin内部的MachineKeyProtector实现(因为它是内部类,无法直接引用)
public class MachineKeyProtector : IDataProtector
{
    private readonly string[] _purposes;

    public MachineKeyProtector(params string[] purposes)
    {
        _purposes = purposes;
    }

    public byte[] Protect(byte[] userData)
    {
        return MachineKey.Protect(userData, _purposes);
    }

    public byte[] Unprotect(byte[] protectedData)
    {
        return MachineKey.Unprotect(protectedData, _purposes);
    }
}

步骤2:修改WebAPI的Bearer认证配置

var OAuthOptions = new OAuthBearerAuthenticationOptions 
{ 
    AuthenticationMode = AuthenticationMode.Active,
    AuthenticationType = OAuthDefaults.AuthenticationType,
    // 使用自定义的认证提供器,传入和MVC一致的Auth_type
    Provider = new CookieTicketBearerAuthenticationProvider("你的Auth_type值") 
}; 
app.UseOAuthBearerAuthentication(OAuthOptions);

配置完成后,你之前的前端代码不需要任何修改,直接把.AspNet.ApplicationCookie的值作为Bearer Token发送即可,WebAPI会自动解密并验证身份。


内容的提问来源于stack exchange,提问作者hungryMind

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:05:18