我正在使用身份服务器4作为令牌服务的asp.net MVC应用程序.我有一个api,它有一些安全的资源.我想为api实现角色(授权).我想确保只有具有有效角色的授权资源才能访问api端点,否则会获得401(未经授权的错误).
这是我的配置:
客户
new Client() { ClientId = "mvcClient",ClientName = "MVC Client",AllowedGrantTypes = GrantTypes.HybridAndClientCredentials,ClientSecrets = new List<Secret>() { new Secret("secret".Sha256()) },RequireConsent = false; // where to redirect to after login RedirectUris = { "http://localhost:5002/signin-oidc" },// where to redirect to after logout PostlogoutRedirectUris = { "http://localhost:5002" },AllowedScopes = { StandardScopes.OpenId.Name,StandardScopes.Profile.Name,StandardScopes.OfflineAccess.Name,StandardScopes.Roles.Name,"API" } }
领域
return new List<Scope>() { StandardScopes.OpenId,// subject id StandardScopes.Profile,// first name,last name StandardScopes.OfflineAccess,// requesting refresh tokens for long lived API access StandardScopes.Roles,new Scope() { Name = "API",Description = "API desc",Type = ScopeType.Resource,Emphasize = true,IncludeAllClaimsForUser = true,Claims = new List<ScopeClaim> { new ScopeClaim(ClaimTypes.Name),new ScopeClaim(ClaimTypes.Role) } } };
new InMemoryUser() { Subject = "1",Username = "testuser",Password = "password",Claims = new List<Claim>() { new Claim("name","Alice"),new Claim("Website","http://alice.com"),new Claim(JwtClaimTypes.Role,"admin") } }
在服务器启动中我添加了这个:
services.AddIdentityServer()
.AddTemporarySigningCredential()
.AddSigningCredential(CERT)
.AddInMemoryClients(Config.GetClients())
.AddInMemoryScopes(Config.GetScopes())
.AddInMemoryUsers(Config.GetUsers())
在api启动中,我有这个:
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions() { Authority = "http://localhost:5000",ScopeName = "NamfusAPI",RequireHttpsMetadata = false });
在api控制器中,我有这个:
[Authorize(Roles = "admin")] public IActionResult Get() { return new JsonResult(from c in User.Claims select new {c.Type,c.Value }); }
在MVC客户端启动中,我有这个:
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear(); app.UseCookieAuthentication(new CookieAuthenticationOptions() { AuthenticationScheme = "Cookies" }); var oidcOptions = new OpenIdConnectOptions() { AuthenticationScheme = "oidc",SignInScheme = "Cookies",Authority = "http://localhost:5000",RequireHttpsMetadata = false,ClientId = "mvcClient",ClientSecret = "secret",SaveTokens = true,GetClaimsFromUserInfoEndpoint = true,ResponseType = "code id_token",// hybrid flow }; oidcOptions.Scope.Clear(); oidcOptions.Scope.Add("openid"); oidcOptions.Scope.Add("profile"); oidcOptions.Scope.Add("NamfusAPI"); oidcOptions.Scope.Add("offline_access"); oidcOptions.Scope.Add("roles");
我试图像这样调用api:
public async Task<IActionResult> CallApiUsingUserAccessToken() { var accessToken = await HttpContext.Authentication.GetTokenAsync("access_token"); var client = new HttpClient(); client.SetBearerToken(accessToken); var content = await client.GetStringAsync("http://localhost:5001/identity"); ViewBag.Json = JArray.Parse(content).ToString(); return View("json"); }
我得到访问令牌但是当调用api(身份/获取)时,我得到302错误禁止(在chrome网络中它显示500内部服务器错误).如果我从中更改API Authorize属性
[Authorize(Roles = "admin")] public IActionResult Get()
到(没有角色):
[Authorize] public IActionResult Get()
它工作,我从mvc应用程序中的api获取数据.如何在此代码中应用角色.
请建议.
解决方法
首先,您需要在OpenIdConnectOptions()中请求“API”范围.
oidcOptions.Scope.Add("API");
要么
Scope = { "API","offline_access",..},
然后,您需要检查角色声明是否包含在API控制器可用的声明列表中(不要在authorize属性中应用角色过滤器.在控制器方法中放置一个调试点并展开User属性).检查您收到的角色声明的类型(在声明集合中列出)是否与User.Identity.RoleClaimType属性匹配
如果您拥有的角色声明类型与User.Identity.RoleClaimType不匹配,则使用角色过滤器的authorize属性将不起作用.您可以在IdentityServerAuthenticationOptions()中设置正确的RoleClaimType,如下所示
app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions { Authority = "http://localhost:5000",ScopeName = "API",RoleClaimType = ClaimTypes.Role,RequireHttpsMetadata = false });