第五节:IdentityServer4的Pkce机制、令牌刷新机制、混合受权模式

一. PKCE机制html

1. 准备web

(1). IDS4_Server1:认证受权服务器浏览器

(2). MvcClient1:web客户端安全

 而后将上述两个项目配置成受权码模式(如何配置见上一节 IdentityServer4受权码模式介绍和代码实操演练服务器

PS: PKCE机制是在受权码模式的基础上,增长了几个验证参数,使其更加安全。ide

2. 代码配置post

(1).IDS4_Server1中的Config1,新增 RequirePkce = true, 开启Pkce受权校验。测试

(2).MvcClient1中的ConfigureServices中, 新增options.UsePkce = true;开启Pkce. (默认就是true,因此能够省略)ui

PS:实际上在上一节的受权码模式中已经开启了pkce,只是没有单独点明增长的参数的含义。url

3. 剖析测试

(1).在导向认证服务器的请求和确认受权页面的请求中,新增两个参数:code_challenge 和 code_challenge_method.

(2).客户端携带受权码请求认证服务器的时候,携带的参数中新增: code_verifier

 

二. 令牌刷新机制

1. 准备

(1). IDS4_Server1:认证受权服务器

(2). MvcClient1:web客户端

 而后将上述两个项目配置成受权码模式(如何配置见上一节 IdentityServer4受权码模式介绍和代码实操演练

2.代码配置

(1).IDS4_Server1中的Config1,新增以下代码:

(2).MvcClient1中的ConfigureServices中,新增以下代码:

options.Scope.Add(OpenIdConnectScope.OfflineAccess); options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1); options.TokenValidationParameters.RequireExpirationTime = true;

 

3.运行结果

页面显示多了个:  refresh_token

注意过时时间:Token.expires_at

 

 

 

三. 混合受权模式

1. 背景

  access token 不含有任何关于身份认证的信息(用户声明信息),access token 的生命期可能会很是的长,即便用户离开了它仍有可能有效,它还有可能被用于无最终用户参与的状况,还有一种状况就是 access token 可能会被其它的客户端应用借用。因此,不管客户端是如何获得的 access token, 它都没法从 access token 里获得最终用户的信息以及最终用户的身份认证状态(用户声明信息)。

  在 OAuth2.0 里,access token 不是为客户端准备的,它对于客户端应该是不透明的, 可是客户端也须要从 access token 获得一些用户信息,实际上客户端应用只是 access token 的展现者, access token

真正的目标观众是被保护的资源.

  在 OpenID Connect 里,加了一个 ID Token 令牌,它会和 access token 一同发送给客户端用,用于识别当前用户是他声称的的用户.

2. 核心代码

IDS4服务器:AllowedGrantTypes = GrantTypes.Hybrid

代码分享:

/// <summary>
    /// 混合模式 /// </summary>
    public class Config2 { /// <summary>
        /// IDS资源 /// </summary>
        /// <returns></returns>
        public static IEnumerable<IdentityResource> GetIds() { return new List<IdentityResource> { new IdentityResources.OpenId(), new IdentityResources.Profile(), }; } /// <summary>
        /// 可使用ID4 Server 客户端资源 /// </summary>
        /// <returns></returns>
        public static IEnumerable<Client> GetClients() { List<Client> clients = new List<Client>() { new Client { ClientId = "client1", ClientSecrets = { new Secret("123456".Sha256()) }, //混合模式
                    AllowedGrantTypes = GrantTypes.Hybrid, //须要确认受权
                    RequireConsent = true, //关闭PKCE校验(默认是true)
                    RequirePkce = false, //容许token经过浏览器
                    AllowAccessTokensViaBrowser=true, // where to redirect to after login(登陆)
                    RedirectUris = { "http://127.0.0.1:7072/signin-oidc" }, // where to redirect to after logout(退出)
                    PostLogoutRedirectUris = { "http://127.0.0.1:7072/signout-callback-oidc" }, //容许的范围
                    AllowedScopes = new List<string> { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile }, AlwaysIncludeUserClaimsInIdToken=true, //容许脱机访问
                    AllowOfflineAccess=true, //accessToken有效期,默认事3600秒,即1小时 (单位:秒)
                    AccessTokenLifetime = 600 } }; return clients; } /// <summary>
        /// 定义可使用ID4的用户资源 /// </summary>
        /// <returns></returns>
        public static List<TestUser> GetUsers() { var address = new { street_address = "One Hacker Way", locality = "Heidelberg", postal_code = 69118, country = "Germany" }; return new List<TestUser>() { new TestUser { SubjectId = "001", Username = "ypf1",    //帐号
                        Password = "123456",  //密码
                        Claims = { new Claim(JwtClaimTypes.Name, "Alice Smith"), new Claim(JwtClaimTypes.GivenName, "Alice"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, "AliceSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://alice.com"), new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json) } }, new TestUser { SubjectId = "002", Username = "ypf2", Password = "123456", Claims = { new Claim(JwtClaimTypes.Name, "Bob Smith"), new Claim(JwtClaimTypes.GivenName, "Bob"), new Claim(JwtClaimTypes.FamilyName, "Smith"), new Claim(JwtClaimTypes.Email, "BobSmith@email.com"), new Claim(JwtClaimTypes.EmailVerified, "true", ClaimValueTypes.Boolean), new Claim(JwtClaimTypes.WebSite, "http://bob.com"), //这是新的序列化模式哦
                            new Claim(JwtClaimTypes.Address, JsonSerializer.Serialize(address), IdentityServerConstants.ClaimValueTypes.Json) } } }; } }
View Code

Mvc客户端:options.ResponseType = OpenIdConnectResponseType.CodeIdToken

代码分享:

 { JwtSecurityTokenHandler.DefaultMapInboundClaims = false; //添加Cookie认证
                services.AddAuthentication(options => { options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc"; }) .AddCookie("Cookies") //经过OIDC协议远程请求认证
                .AddOpenIdConnect("oidc", options => { options.Authority = "http://127.0.0.1:7070";   //认证受权服务器地址
                    options.RequireHttpsMetadata = false; options.ClientId = "client1";    //客户端ID
                    options.ClientSecret = "123456"; //客户端秘钥 //混合模式
                    options.ResponseType = OpenIdConnectResponseType.CodeIdToken; options.ResponseMode = OpenIdConnectResponseMode.FormPost; options.SaveTokens = true; //开启token时间的校验
 options.Scope.Add(OpenIdConnectScope.OfflineAccess); options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(1); options.TokenValidationParameters.RequireExpirationTime = true; }); }
View Code

特别注意:要关闭pkce的验证,不然会报错 code challenge required. 代码:RequirePkce = false

 

 

 

 

!

  • 做       者 : Yaopengfei(姚鹏飞)
  • 博客地址 : http://www.cnblogs.com/yaopengfei/
  • 声     明1 : 若有错误,欢迎讨论,请勿谩骂^_^。
  • 声     明2 : 原创博客请在转载时保留原文连接或在文章开头加上本人博客地址,不然保留追究法律责任的权利。
相关文章
相关标签/搜索