一. 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) } } }; } }
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; }); }
特別注意:要關閉pkce的驗證,不然會報錯 code challenge required. 代碼:RequirePkce = false
!
- 做 者 : Yaopengfei(姚鵬飛)
- 博客地址 : http://www.cnblogs.com/yaopengfei/
- 聲 明1 : 若有錯誤,歡迎討論,請勿謾罵^_^。
- 聲 明2 : 原創博客請在轉載時保留原文連接或在文章開頭加上本人博客地址,不然保留追究法律責任的權利。