ASP.NET Core 2.0混合认证场景下,API如何从JWT令牌获取声明?
解决ASP.NET Core 2.0混合认证中API端获取JWT声明的问题
嘿,我来帮你搞定这个混合认证的问题!其实API端获取JWT声明的方式和Web端用Cookie认证的方式几乎完全一样,核心都是通过HttpContext.User来访问声明,但需要先确保API请求使用的是JWT认证方案,我来一步步给你讲清楚:
一、API端获取JWT声明的基本方式
只要API请求通过JWT认证成功,你就可以像Web控制器里那样直接用User对象(或者HttpContext.User)来获取声明,比如:
[ApiController] [Route("api/[controller]")] public class UserController : ControllerBase { [HttpGet("profile")] public IActionResult GetUserProfile() { // 获取所有声明 var allClaims = User.Claims.Select(c => new { c.Type, c.Value }); // 获取特定声明(比如用户名、邮箱) var username = User.FindFirst(ClaimTypes.Name)?.Value; var email = User.FindFirst(ClaimTypes.Email)?.Value; return Ok(new { Username = username, Email = email, AllClaims = allClaims }); } }
二、关键:确保API请求使用JWT认证方案
你当前的配置里默认认证方案是myApp_cookie,所以API请求即使带了JWT令牌,也会走Cookie认证逻辑,导致拿不到JWT里的声明。有两种方式解决这个问题:
方式1:给API控制器/Action指定认证方案
直接在API控制器或者单个Action上添加[Authorize]特性,并明确指定使用JwtBearer方案:
[ApiController] [Route("api/[controller]")] // 给整个API控制器指定JWT认证方案 [Authorize(AuthenticationSchemes = "JwtBearer")] public class UserController : ControllerBase { // ... 你的API方法 }
这种方式简单直接,适合API和Web路由区分明确的场景。
方式2:配置动态认证方案(推荐)
通过PolicyScheme让系统自动根据请求判断使用Cookie还是JWT认证,不用手动给每个API加特性。修改你的MyAuthenticationConfig方法如下:
public static void MyAuthenticationConfig(IServiceCollection services, IConfiguration configuration) { services.AddAuthentication(options => { // 设置动态方案为默认认证/挑战方案 options.DefaultAuthenticateScheme = "DynamicAuthScheme"; options.DefaultChallengeScheme = "DynamicAuthScheme"; }) // 添加动态选择的PolicyScheme .AddPolicyScheme("DynamicAuthScheme", "Dynamic Authentication", options => { options.ForwardDefaultSelector = context => { // 判断请求头是否包含Bearer令牌,是的话用JWT认证 var authHeader = context.Request.Headers["Authorization"].FirstOrDefault(); if (!string.IsNullOrEmpty(authHeader) && authHeader.StartsWith("Bearer ")) { return "JwtBearer"; } // 其他情况默认用Cookie认证 return "myApp_cookie"; }; }) // 以下是你原来的Cookie、OAuth、JWT配置,保持不变 .AddCookie("myApp_cookie", options => { options.AccessDeniedPath = "/Unauthorized"; options.LoginPath = "/Login"; }) .AddCookie("social_auth_cookie") .AddOAuth("LinkedIn", options => { options.SignInScheme = "social_auth_cookie"; options.ClientId = "my_client_id"; options.ClientSecret = "my_secret"; options.CallbackPath = "/linkedin-callback"; options.AuthorizationEndpoint = "https://www.linkedin.com/oauth/v2/authorization"; options.TokenEndpoint = "https://www.linkedin.com/oauth/v2/accessToken"; options.UserInformationEndpoint = "https://api.linkedin.com/v1/people/~:(id,first-name,last-name,email-address,picture-url,picture-urls::(original))"; options.Scope.Add("r_basicprofile"); options.Scope.Add("r_emailaddress"); options.Events = new OAuthEvents { OnCreatingTicket = OnCreatingTicketLinkedInCallBack, OnTicketReceived = OnTicketReceivedCallback }; }) .AddFacebook(options => { options.SignInScheme = "social_auth_cookie"; options.AppId = "my_app_is"; options.AppSecret = "my_secret"; options.Events = new OAuthEvents { OnCreatingTicket = OnCreatingTicketFacebookCallback, OnTicketReceived = OnTicketReceivedCallback }; }) .AddGoogle(options => { options.SignInScheme = "social_auth_cookie"; options.ClientId = "my_id.apps.googleusercontent.com"; options.ClientSecret = "my_secret"; options.CallbackPath = "/google-callback"; options.Events = new OAuthEvents { OnCreatingTicket = OnCreatingTicketGoogleCallback, OnTicketReceived = OnTicketReceivedCallback }; }) .AddJwtBearer("JwtBearer", jwtBearerOptions => { jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters { ValidateIssuerSigningKey = true, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("my_secret")), ValidateIssuer = true, ValidIssuer = "my-api", ValidateAudience = true, ValidAudience = "my-client", ValidateLifetime = true, ClockSkew = TimeSpan.FromMinutes(5) }; }); }
这个配置会自动检测请求:如果请求头里有Authorization: Bearer {token},就用JWT认证;否则用Cookie认证,完美适配你的混合场景。
三、验证一下
当API请求携带正确的JWT令牌时,User.Identity.IsAuthenticated会返回true,并且User.Claims会包含JWT里的所有声明,和你在Web端用Cookie获取声明的方式完全一致。
内容的提问来源于stack exchange,提问作者Sam
相关产品推荐
相关产品推荐

