IdentityServer4系列(05)【授权方式】

IdentityServer4系列(05)【授权方式】基于角色验证服务器用户 添加新的 claim newClaim JwtClaimType Role 管理员 publicclassT publicstatic TestUser Users newList TestUser newTestUser SubjectId Username alice Passwor TestUser TestUser

基于角色

验证服务器

  • 用户,添加新的claim: new Claim(JwtClaimTypes.Role, "管理员")
public class TestUsers { 
    public static List<TestUser> Users = new List<TestUser> { 
    new TestUser{ 
   SubjectId = "", Username = "alice", Password = "alice", Claims = { 
    new Claim(JwtClaimTypes.Name, "Alice Smith"), new Claim(JwtClaimTypes.GivenName, "Alice"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, ""), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://alice.com"), new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json), new Claim(JwtClaimTypes.Role, "管理员") } }, new TestUser{ 
   SubjectId = "", Username = "bob", Password = "bob", Claims = { 
    new Claim(JwtClaimTypes.Name, "Bob Smith"), new Claim(JwtClaimTypes.GivenName, "Bob"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, ""), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://bob.com"), new Claim(JwtClaimTypes.Address, @"{ 'street_address': 'One Hacker Way', 'locality': 'Heidelberg', 'postal_code': 69118, 'country': 'Germany' }", IdentityServer4.IdentityServerConstants.ClaimValueTypes.Json), new Claim("location", "somewhere"), new Claim(JwtClaimTypes.Role, "普通用户") } } }; } 
  • Config.cs, 添加一个IdentityResource, 添加一个scope
public static IEnumerable<IdentityResource> GetIdentityResources() { 
    return new IdentityResource[] { 
    new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Address(), new IdentityResources.Phone(), new IdentityResources.Email(), new IdentityResource("roles","角色", new List<string>{ 
    JwtClaimTypes.Role}) //这里的roles指scope }; } new Client { 
    ClientId = "hybrid client", ClientName = "ASP.NET Core Hybrid client", ClientSecrets= { 
    new Secret("hybrid_secret".Sha256())}, AllowedGrantTypes=GrantTypes.Hybrid, RedirectUris = { 
    "http://localhost:7000/signin-oidc" }, PostLogoutRedirectUris = { 
    "http://localhost:7000/signout-callback-oidc" }, AllowOfflineAccess = true, AlwaysIncludeUserClaimsInIdToken=true, AllowedScopes = { 
    "api1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Address, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Phone, "roles" } } 

web服务器

  • Startup.cs, 在cookies中配置授权失败的转向页,在OpenIdConnect中配置有关roles
services.AddAuthentication(options => { 
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { 
    options.AccessDeniedPath = "/Authorization/AccessDenied"; }) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { 
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ClientId = "hybrid client"; options.ClientSecret = "hybrid_secret"; options.SaveTokens = true; options.ResponseType = "code id_token"; options.Scope.Clear(); options.Scope.Add("api1"); options.Scope.Add(OidcConstants.StandardScopes.OpenId); options.Scope.Add(OidcConstants.StandardScopes.Profile); options.Scope.Add(OidcConstants.StandardScopes.Email); options.Scope.Add(OidcConstants.StandardScopes.Phone); options.Scope.Add(OidcConstants.StandardScopes.Address); options.Scope.Add(OidcConstants.StandardScopes.OfflineAccess); options.Scope.Add("roles"); //把一些被自动过滤掉的claim找回来 options.ClaimActions.Remove("nbf"); options.ClaimActions.Remove("amr"); options.ClaimActions.Remove("exp"); //删除一些不需要的claim options.ClaimActions.DeleteClaim("sid"); options.ClaimActions.DeleteClaim("sub"); options.ClaimActions.DeleteClaim("idp"); //有关用户的roles options.TokenValidationParameters = new TokenValidationParameters { 
    NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role }; }); 
  • 在控制器中
[Authorize(Roles = "管理员,普通用户")] 

基于策略,将多个claim组合在一起

在Startup.cs中的services.AddAuthorization中配置策略

//配置策略 services.AddAuthorization(options => { 
    options.AddPolicy("SmithInSomewhere", builder => { 
    builder.RequireAuthenticatedUser(); builder.RequireClaim(JwtClaimTypes.FamilyName, "Smith"); //这里值可以有多个,逗号分隔 builder.RequireClaim("location", "somewhere"); //这个不是标准claim哦 }); }); 

这里自定义的claim叫做location,位于某个scope中,这个scope需要在services.AddAuthentication中加上。

services.AddAuthentication(options => { 
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options => { 
    options.AccessDeniedPath = "/Authorization/AccessDenied"; }) .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => { 
    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.Authority = "http://localhost:5000"; options.RequireHttpsMetadata = false; options.ClientId = "hybrid client"; options.ClientSecret = "hybrid_secret"; options.SaveTokens = true; options.ResponseType = "code id_token"; options.Scope.Clear(); options.Scope.Add("api1"); options.Scope.Add(OidcConstants.StandardScopes.OpenId); options.Scope.Add(OidcConstants.StandardScopes.Profile); options.Scope.Add(OidcConstants.StandardScopes.Email); options.Scope.Add(OidcConstants.StandardScopes.Phone); options.Scope.Add(OidcConstants.StandardScopes.Address); options.Scope.Add(OidcConstants.StandardScopes.OfflineAccess); options.Scope.Add("roles"); options.Scope.Add("locations"); //把一些被自动过滤掉的claim找回来 options.ClaimActions.Remove("nbf"); options.ClaimActions.Remove("amr"); options.ClaimActions.Remove("exp"); //删除一些不需要的claim options.ClaimActions.DeleteClaim("sid"); options.ClaimActions.DeleteClaim("sub"); options.ClaimActions.DeleteClaim("idp"); //有关用户的roles options.TokenValidationParameters = new TokenValidationParameters { 
    NameClaimType = JwtClaimTypes.Name, RoleClaimType = JwtClaimTypes.Role }; }); 

以上的locations这个scope需要在验证服务器上设置。

public static IEnumerable<IdentityResource> GetIdentityResources() { 
    return new IdentityResource[] { 
    new IdentityResources.OpenId(), new IdentityResources.Profile(), new IdentityResources.Address(), new IdentityResources.Phone(), new IdentityResources.Email(), new IdentityResource("roles","角色", new List<string>{ 
    JwtClaimTypes.Role}), //这里的roles指scope new IdentityResource("locations","地点", new List<string>{ 
    "location"} ) }; } new Client { 
    ClientId = "hybrid client", ClientName = "ASP.NET Core Hybrid client", ClientSecrets= { 
    new Secret("hybrid_secret".Sha256())}, AllowedGrantTypes=GrantTypes.Hybrid, RedirectUris = { 
    "http://localhost:7000/signin-oidc" }, PostLogoutRedirectUris = { 
    "http://localhost:7000/signout-callback-oidc" }, AllowOfflineAccess = true, AlwaysIncludeUserClaimsInIdToken=true, AllowedScopes = { 
    "api1", IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, IdentityServerConstants.StandardScopes.Address, IdentityServerConstants.StandardScopes.Email, IdentityServerConstants.StandardScopes.Phone, "roles", "locations" } } 

更复杂的策略

  • 一个action可以有多个Policy作用
  • 一个Policy, 通过RequireAuthenticatedUser,RequireClaim, IAuthorizationRequirement生成,
  • 一个IAuthorizationRequirement中有多个AuthorizationHandler

首先需要实现IAuthorizationRequirement

public class SmithInSomewhereRequirement : IAuthorizationRequirement { 
    public SmithInSomewhereRequirement() { 
    } } 

其次需要一个AuthorizationHandler

 public class SmithInSomewhereHandler : AuthorizationHandler<SmithInSomewhereRequirement> { 
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SmithInSomewhereRequirement requirement) { 
    //var filterContext = context.Resource as AuthorizationFilterContext; //if(filterContext==null) //{ 
    // context.Fail(); // return Task.CompletedTask; //} var familyName = context.User.Claims.FirstOrDefault(c => c.Type == JwtClaimTypes.FamilyName)?.Value; var location = context.User.Claims.FirstOrDefault(t => t.Type == "location")?.Value; if(familyName == "Smith" && location == "somewhere" && context.User.Identity.IsAuthenticated) { 
    context.Succeed(requirement); return Task.CompletedTask; } context.Fail(); return Task.CompletedTask; } } 

最后在startup.cs中设置:

//配置策略 services.AddAuthorization(options => { 
    //options.AddPolicy("SmithInSomewhere", builder => { 
    // builder.RequireAuthenticatedUser(); // builder.RequireClaim(JwtClaimTypes.FamilyName, "Smith"); //这里值可以有多个,逗号分隔 // builder.RequireClaim("location", "somewhere"); //这个不是标准claim哦 //}); options.AddPolicy("SmithInSomewhere", builder => { 
    builder.AddRequirements(new SmithInSomewhereRequirement()); }); }); 
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232591.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 中标麒麟操作系统安装教程_中标麒麟内核是centos

    中标麒麟操作系统安装教程_中标麒麟内核是centos为什么80%的码农都做不了架构师?>>>…

    2022年8月30日
    2
  • usb-c接口和雷电3接口有什么区别(type-c和雷电3的区别)

    缘起随着小新pro发布,看到带了全功能的type-c接口,一直搞不懂什么type-c还有什么全功能,半功能?和雷电3又有什么区别,雷电3又有什么全速,半速。由于搞不清,所以网上看了很多资料,这里总结一下以备后续查阅说说usb3.1和雷电3usb接口大家再熟悉不过了,就是我们经常说的这种的但其实这个样子的全称是USBType-A,除此之外还有USBType-B,USBType-C…

    2022年4月18日
    108
  • 大型架构及配置技术之Ansible

    大型架构及配置技术之Ansible

    2021年6月9日
    96
  • Linux中搭建DNS服务器

    Linux中搭建DNS服务器目录DNS域传送漏洞域名空间结构DNS解析过程各种解析记录DNS服务器的安装与部署主从DNS服务器的搭建:转发DNS服务器的配置DNSDNS(DomainNameService)域名解析服务,就是将域名和ip之间做相应的转换,利用TCP和UDP的53号端口DNS系统作用:正向解析:根据域名查找对应的ip地址 反向解析:根据ip地址查…

    2022年6月4日
    29
  • 服务器ssh免密钥登陆(vscode远程连接服务器)

    VScode实现远程查看代码要使用一些插件,我用的是Remote-SSH,安装很简单,推荐看下下面的博客,写的很详细:https://blog.csdn.net/u010417914/article/details/96918562重要的是遇到的一些问题:1.我的服务器用的是Ubuntu18.04,生成rsa公钥和私钥后,注意要以附加到文件尾部的方式把公钥拷贝到…

    2022年4月14日
    55
  • AT命令集详解_at命令详解

    AT命令集详解_at命令详解1.AT的历史与应用   1.1AT的历史AT命令集是由拨号调制解调器(MODEM)的发明者贺氏公司(Hayes)为了控制Modem发明的控制协议.AT是Attention的缩写,协议本身采用文本.每个命令均以AT打头,因此得名.这段历史参见http://en.wikipedia.org/wiki/Hayes_command_set 随着网络升级为宽带,速度很低拨号MODEM

    2025年7月25日
    5

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号