IdentityServer4同站点权限分离:如何判断用户认证所用客户端
解决同一站点区分IdentityServer4客户端并控制访问权限的问题
首先,核心思路是利用IdentityServer4在认证令牌中自带的client_id Claim来区分用户/请求来自哪个客户端,然后通过自定义授权策略实现权限隔离。下面一步步拆解实现方案:
一、关键原理:client_id Claim的存在
IdentityServer4在生成ID Token和Access Token时,会自动把当前请求的客户端ID以client_id的Claim形式嵌入令牌中:
- 通过
mvc客户端登录的站内用户,其Cookie认证的Claims里会包含client_id: mvc - 通过
sapi客户端调用API的请求,其JWT令牌里会包含client_id: sapi
我们只需要基于这个Claim做权限判断即可。
二、配置自定义授权策略
在你的.NET Core站点的Startup.cs(.NET Core 2.x)中,添加针对应用和API的不同授权策略:
services.AddAuthorization(options => { // 仅允许mvc客户端的用户访问应用页面 options.AddPolicy("MvcClientOnly", policy => { policy.RequireClaim("client_id", "mvc"); }); // 允许mvc和sapi客户端访问API options.AddPolicy("ApiAccess", policy => { policy.RequireClaim("client_id", "mvc", "sapi"); }); });
三、为应用和API分别应用策略
1. 站内应用页面(MVC控制器)
给需要登录才能访问的应用控制器/Action加上[Authorize]并指定MvcClientOnly策略:
[Authorize(Policy = "MvcClientOnly")] public class HomeController : Controller { // 站内用户才能访问的应用页面逻辑 }
这样一来,即使外部应用拿到了合法令牌,也无法访问这些页面——因为它们的client_id是sapi,不满足策略要求。
2. API接口
给API控制器指定ApiAccess策略,同时注意指定JWT认证方案(因为API用Bearer令牌认证,和MVC的Cookie认证区分开):
[Authorize(AuthenticationSchemes = "Bearer", Policy = "ApiAccess")] [Route("api/[controller]")] public class ValuesController : ControllerBase { // 站内用户和外部应用都能访问的API逻辑 }
四、代码中手动判断客户端ID(可选)
如果需要在业务逻辑里主动区分客户端来源,可以直接从当前用户的Claims中提取:
var clientId = User.Claims.FirstOrDefault(c => c.Type == "client_id")?.Value; if (clientId == "mvc") { // 处理站内用户的专属逻辑 } else if (clientId == "sapi") { // 处理外部应用的专属逻辑 }
五、补充:确保站点的认证中间件配置正确
因为你的站点同时承载MVC应用和API,需要分别配置两种认证方案:
// MVC应用的Cookie+OIDC认证 services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") .AddOpenIdConnect("oidc", options => { options.Authority = "http://localhost:5000"; // 你的IdentityServer地址 options.ClientId = "mvc"; options.ClientSecret = "secret"; options.ResponseType = "code id_token"; options.SaveTokens = true; options.Scope.Add("sapi"); options.Scope.Add("offline_access"); }); // API的JWT Bearer认证 services.AddAuthentication("Bearer") .AddJwtBearer("Bearer", options => { options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.Audience = "sapi"; });
这样配置后,就能完美实现你的需求:同一URL下,站内用户通过mvc客户端登录后可访问应用和API,外部应用通过sapi客户端只能访问API,无法进入应用页面。
内容的提问来源于stack exchange,提问作者pdube
相关产品推荐
相关产品推荐

