轉自:http://www.jianshu.com/p/fde63052a3a5css
本教程會介紹如何在前端JS程序中集成IdentityServer
。由於全部的處理都在前端,咱們會使用一個JS庫oidc-client-js, 來處理諸如獲取,驗證tokens的工做。html
本教程的代碼在這裏.前端
本教程分爲三大塊:node
IdentityServer
進行認證IdentityServer
進行認證第一部分,咱們專一在如何前端認證。咱們準備了兩個項目,一個是JS前端程序,一個是IdentityServer
.jquery
在Visual Studio中建立一個空Web應用。git
注意項目的URL,後面須要在瀏覽器中使用:github
在Visual Studio中建立另一個空Web應用程序來託管IdentityServer
.web
切換到項目屬性,啓用SSL:ajax
提醒
不要忘了把Web程序的啓動URL改爲https的連接(具體連接參看你項目的SSL URL).數據庫
譯者注: identityserver3不支持http的網站,必須有SSL保護
IdentityServer is based on OWIN/Katana and distributed as a NuGet package. To add it to the newly created web host, install the following two packages:
IdentityServer是一個OWIN/Katana的中間件,經過Nuget分發。運行下面的命令安裝nuget包到IdentityServer
託管程序。
Install-Package Microsoft.Owin.Host.SystemWeb Install-Package IdentityServer3
IdentityServer
須要知道客戶端的一些信息,能夠經過返回Client
對象集合告訴IdentityServer
.
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { Enabled = true, ClientName = "JS Client", ClientId = "js", Flow = Flows.Implicit, RedirectUris = new List<string> { "http://localhost:56668/popup.html" //請檢查端口號,確保和你剛纔建立的JS項目同樣 }, AllowedCorsOrigins = new List<string> { "http://localhost:56668" }, AllowAccessToAllScopes = true } }; } }
特別注意AllowedCorsOrigins
屬性,上面代碼的設置,讓IdentityServer
接受這個指定網站的認證請求。 譯者注: 考慮到安全性, 網站通常不接受不一樣域的請求,這裏是設置能夠接受指定的跨域請求
popup.html
會在後面詳細講解,這裏你照樣填就行了.
備註 如今這個客戶端能夠接受任何做用域(AllowAccessToAllScopes
設置爲true).在生產環境,必須經過AllowScopes
來限制做用域範圍。
接下來,咱們在IdentityServer裏硬編碼一些用戶--一樣的,這個能夠經過一個簡單的C#類來實現。生產環境中,咱們應該從數據庫裏獲取用戶信息。 IdentityServer也直接支持ASP.NET 的Identity和MembershipReboot.
public static class Users { public static List<InMemoryUser> Get() { return new List<InMemoryUser> { new InMemoryUser { Username = "bob", Password = "secret", Subject = "1", Claims = new[] { new Claim(Constants.ClaimTypes.GivenName, "Bob"), new Claim(Constants.ClaimTypes.FamilyName, "Smith"), new Claim(Constants.ClaimTypes.Email, "bob.smith@email.com") } } }; } }
最後,咱們加上做用域。 純粹認證功能,咱們只須要支持標準的OIDC做用域。未來咱們受權API調用,咱們會建立咱們本身的做用域。
public static class Scopes { public static List<Scope> Get() { return new List<Scope> { StandardScopes.OpenId, StandardScopes.Profile }; } }
IdentityServer
是一個OWIN中間件,須要在Startup類中配置。這個教程中,咱們會配置客戶端,用戶,做用域,認證證書和一些配置選項。
在生產環境須要從windows證書倉庫或者其它安全的地方裝載證書。簡化起見,這個教程咱們把證書文件直接保存在項目中。(演示用的證書能夠從 這裏下載.下載後直接添加到項目中,並把文件的Copy to Output Directory
property 改成 Copy always
).
關於如何從Azure中裝載證書,請看 這裏.
public class Startup { public void Configuration(IAppBuilder app) { app.UseIdentityServer(new IdentityServerOptions { SiteName = "Embedded IdentityServer", SigningCertificate = LoadCertificate(), Factory = new IdentityServerServiceFactory() .UseInMemoryUsers(Users.Get()) .UseInMemoryClients(Clients.Get()) .UseInMemoryScopes(Scopes.Get()) }); } private static X509Certificate2 LoadCertificate() { return new X509Certificate2( Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"bin\Config\idsrv3test.pfx"), "idsrv3test"); } }
完成上面的步驟後,一個全功能的IdentityServer
就行了,你能夠瀏覽探索端點
來了解相信配置信息。
最後不要忘了在Web.config中添加RAMMFAR支持,不然有一些內嵌的資源沒法被IIS裝載:
<system.webServer> <modules runAllManagedModulesForAllRequests="true" /> </system.webServer>
咱們使用下面的第三方庫來簡化咱們的JS客戶端開發:
咱們經過npm-- the Node.js 前段包管理器--來安裝這些前端庫. 若是你尚未安裝npm, 你能夠按照 npm安裝說明來安裝npm.
npm安裝好了後,打開命令行(CMD),轉到JSApplication目錄下,運行:
$ npm install jquery $ npm install bootstrap $ npm install oidc-client
npm會把上述包按照到默認目錄node_modules
.
重要npm包通常不會提交到源碼倉庫,若是你是從github倉庫中克隆代碼, 你須要在命令行(cmd)下,轉到JSApplication
目錄,而後運行npm install
來恢復這幾個前端包。
在JSApplication
項目,加入一個基礎的Index.html
文件:
<!DOCTYPE html> <html> <head> <title>JS Application</title> <meta charset="utf-8" /> <link rel="stylesheet" href="node_modules/bootstrap/dist/css/bootstrap.css" /> <style> .main-container { padding-top: 70px; } pre:empty { display: none; } </style> </head> <body> <nav class="navbar navbar-inverse navbar-fixed-top"> <div class="container"> <div class="navbar-header"> <a class="navbar-brand" href="#">JS Application</a> </div> </div> </nav> <div class="container main-container"> <div class="row"> <div class="col-xs-12"> <ul class="list-inline list-unstyled requests"> <li><a href="index.html" class="btn btn-primary">Home</a></li> <li><button type="button" class="btn btn-default js-login">Login</button></li> </ul> </div> </div> <div class="row"> <div class="col-xs-12"> <div class="panel panel-default"> <div class="panel-heading">ID Token Contents</div> <div class="panel-body"> <pre class="js-id-token"></pre> </div> </div> </div> </div> </div> <script src="node_modules/jquery/dist/jquery.js"></script> <script src="node_modules/bootstrap/dist/js/bootstrap.js"></script> <script src="node_modules/oidc-client/dist/oidc-client.js"></script> </body> </html>
和 popup.html
文件:
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8" /> </head> <body> <script src="node_modules/oidc-client/dist/oidc-client.js"></script> </body> </html>
由於oidc-client
能夠打開一個彈出窗口讓用戶登陸,因此咱們作了一個popup頁面
好了,如今零件已經組裝好了,咱們須要加一點邏輯代碼讓它動起來. 感謝UserManager
JS類,它作了大部分骯髒的工做,咱們只要一點簡單代碼就好。
// helper function to show data to the user function display(selector, data) { if (data && typeof data === 'string') { data = JSON.parse(data); } if (data) { data = JSON.stringify(data, null, 2); } $(selector).text(data); } var settings = { authority: 'https://localhost:44300', client_id: 'js', popup_redirect_uri: 'http://localhost:56668/popup.html', response_type: 'id_token', scope: 'openid profile', filterProtocolClaims: true }; var manager = new Oidc.UserManager(settings); var user; manager.events.addUserLoaded(function (loadedUser) { user = loadedUser; display('.js-user', user); }); $('.js-login').on('click', function () { manager .signinPopup() .catch(function (error) { console.error('error while logging in through the popup', error); }); });
簡單瞭解一下這些配置項:
authority
是IdentityServer
的入口URL. 經過這個URL,oidc-client
能夠查詢如何與這個IdentityServer
通訊, 並驗證token的有效性。client_id
這是客戶端標識,認證服務器用這個標識來區別不一樣的客戶端。popup_redirect_uri
是使用signinPopup
方法是的重定向URL。若是你不想用彈出框來登錄,但願用戶能到主登陸界面登錄,那麼你須要使用redirect_uri
屬性和signinRedirect
方法。response_type
定義響應類型,在咱們的例子中,咱們只須要服務器返回身份令牌scope
定義了咱們要求的做用域filterProtocolClaims
告訴oidc-client過濾掉OIDC協議內部用的聲明信息,如: nonce
, at_hash
, iat
, nbf
, exp
, aud
, iss
和 idp
咱們監聽處理Login按鈕的單擊事件,當用戶單擊登錄的時候,打開登錄彈出框(signinPopup
). signinPopup
返回一個Promise
。只有收到用戶信息並驗證經過後纔會標記成功。
有兩種方式獲得identityServer
返回的數據:
userLoaded
事件的參數獲得這個例子中,咱們經過events.addUserLoaded·掛載了
userLoaded事件處理函數,把用戶信息保存到全局的user對象中。這個對象有:
id_token,
scope和
profile`等屬性, 這些屬性包含各類用戶具體的數據。
popup.html
頁面也須要配置下:
new Oidc.UserManager().signinPopupCallback();
登錄內部過程:在index.html
頁面的UserManager
實例會打開一個彈出框,而後把它重定向到登錄頁面。當identityServer
認證好用戶,把用戶信息發回到彈出框,彈出框發現登錄已經成功後自動關閉。
代碼抄到這裏,登錄能夠工做啦:
你能夠把filterProtocolClaims
屬性設置爲false,看看profile
下面會多出那些聲明?
咱們定義了一個email
聲明,可是它好像沒有在咱們的身份令牌裏面?這是由於咱們的JS應用只要了openid
和profile
做用域,沒有包括email
聲明。
若是JS應用想拿到郵件地址,JS應用必須在UserManager
的scopes
屬性中申請獲取email
做用域.
在咱們的例子中,咱們首先須要修改IdentityServer
包含Email做用域,代碼以下:
public static class Scopes { public static List<Scope> Get() { return new List<Scope> { StandardScopes.OpenId, StandardScopes.Profile, // New scope StandardScopes.Email }; } }
在這個教程中,JS應用不須要改,由於咱們申請了全部的做用域。 可是在生產環境中,咱們應該只返回用戶須要的做用域,這種狀況下,客戶端代碼也須要修改。
完成上面的改動後,咱們如今能夠看到email
信息啦:
第二部分,咱們演示如何從JS應用中調用受保護的API。
爲了調用被保護的API,除了身份令牌,咱們還要從IdentityServer獲得訪問令牌,並用這個訪問令牌調用被保護的API。
在Visual Studio中建立一個空應用程序.
API項目的URL須要指定爲 http://localhost:60136
.
在本教程,咱們將建立一個很是簡單的API
首先安裝下面的nuget包:
Install-Package Microsoft.Owin.Host.SystemWeb -ProjectName Api Install-Package Microsoft.Owin.Cors -ProjectName Api Install-Package Microsoft.AspNet.WebApi.Owin -ProjectName Api Install-Package IdentityServer3.AccessTokenValidation -ProjectName Api
注意 IdentityServer3.AccessTokenValidation
包間接依賴於System.IdentityModel.Tokens.Jwt
.在編寫本教程時,若是更新System.IdentityModel.Tokens.Jwt
到5.0.0會致使API項目沒法啓動: 譯者注:在我翻譯的時候好像已經解決這個問題了
解決辦法是把System.IdentityModel.Tokens.Jwt
降級到4.0.2.xxx版本:
Install-Package System.IdentityModel.Tokens.Jwt -ProjectName Api -Version 4.0.2.206221351
如今讓咱們建立Startup
類,並構建OWIN/Katana管道。
public class Startup { public void Configuration(IAppBuilder app) { // Allow all origins app.UseCors(CorsOptions.AllowAll); // Wire token validation app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions { Authority = "https://localhost:44300", // For access to the introspection endpoint ClientId = "api", ClientSecret = "api-secret", RequiredScopes = new[] { "api" } }); // Wire Web API var httpConfiguration = new HttpConfiguration(); httpConfiguration.MapHttpAttributeRoutes(); httpConfiguration.Filters.Add(new AuthorizeAttribute()); app.UseWebApi(httpConfiguration); } }
代碼很直觀,可是咱們仍是仔細看看咱們在管道中用了些什麼:
由於JS應用通常都要跨域,因此咱們啓用了CORS。咱們容許來自任何網站的跨域請求,在生產中,咱們須要限制一下,改爲只容許咱們但願的網站來跨域請求。
API項目須要驗證令牌的有效性,咱們經過IdentityServer3.AccessTokenValidation
包來實現。在指定Authority
屬性後,AccessTokenValidation會自動下載元數據並完成令牌驗證的設置。
2.2版本之後,IdentityServer實現了introspection endpoint 來驗證令牌。這個端點會進行做用域認證,比傳統的令牌驗證更安全。
最後是WebAPI配置。咱們使用AuthroizeAttribute
來指定全部的API請求都須要認證。
如今咱們來加上一個簡單的API方法:
[Route("values")] public class ValuesController : ApiController { private static readonly Random _random = new Random(); public IEnumerable<string> Get() { var random = new Random(); return new[] { _random.Next(0, 10).ToString(), _random.Next(0, 10).ToString() }; } }
咱們在IdentityServer
項目中的Scopes
增長一個api
做用域:
public static class Scopes { public static List<Scope> Get() { return new List<Scope> { StandardScopes.OpenId, StandardScopes.Profile, StandardScopes.Email, // New scope registration new Scope { Name = "api", DisplayName = "Access to API", Description = "This will grant you access to the API", ScopeSecrets = new List<Secret> { new Secret("api-secret".Sha256()) }, Type = ScopeType.Resource } }; } }
新的做用域是資源做用域,也就是說它會在訪問令牌中體現。固然例子中的JS應用不須要修改,由於它請求了所有做用域,可是在生產環境中,應該限制申請那些做用域。
如今咱們更新JS應用,申請新的api
做用域
var settings = { authority: 'https://localhost:44300', client_id: 'js', popup_redirect_uri: 'http://localhost:56668/popup.html', // We add `token` to specify we expect an access token too response_type: 'id_token token', // We add the new `api` scope to the list of requested scopes scope: 'openid profile email api', filterProtocolClaims: true };
修改包括:
response_type
來同時請求身份令牌和訪問令牌api
做用域access_token
屬性獲取,過時時間放在expires_at
屬性上。oidc-client
會處理簽名證書,令牌驗證等麻煩的部分,咱們不須要編寫任何代碼。登錄之後咱們會獲得下面的信息:
拿到訪問令牌,咱們就能夠在JS應用裏調用API了。
[...] <div class="container main-container"> <div class="row"> <div class="col-xs-12"> <ul class="list-inline list-unstyled requests"> <li><a href="index.html" class="btn btn-primary">Home</a></li> <li><button type="button" class="btn btn-default js-login">Login</button></li> <!-- New button to trigger an API call --> <li><button type="button" class="btn btn-default js-call-api">Call API</button></li> </ul> </div> </div> <div class="row"> <!-- Make the existing sections 6-column wide --> <div class="col-xs-6"> <div class="panel panel-default"> <div class="panel-heading">User data</div> <div class="panel-body"> <pre class="js-user"></pre> </div> </div> </div> <!-- And add a new one for the result of the API call --> <div class="col-xs-6"> <div class="panel panel-default"> <div class="panel-heading">API call result</div> <div class="panel-body"> <pre class="js-api-result"></pre> </div> </div> </div> </div> </div>
[...] $('.js-call-api').on('click', function () { var headers = {}; if (user && user.access_token) { headers['Authorization'] = 'Bearer ' + user.access_token; } $.ajax({ url: 'http://localhost:60136/values', method: 'GET', dataType: 'json', headers: headers }).then(function (data) { display('.js-api-result', data); }).catch(function (error) { display('.js-api-result', { status: error.status, statusText: error.statusText, response: error.responseJSON }); }); });
代碼改好了,咱們如今有一個調用API的按鈕和一個顯示API結果的Panel。
注意,訪問令牌會放到Authroization
請求頭裏。
登陸前調用,結果以下:
登錄後調用,結果以下:
登錄前訪問API,JS應用沒有獲得訪問令牌,因此不會添加Authorization
請求頭,那麼訪問令牌驗證中間件不會介入。請求作爲未認證的請求發送到API,全局特性AuthroizeAttribute
會拒絕請求,返回`401未受權錯誤。
登錄後訪問API, 令牌驗證中間件在請求頭中發現了Authorization
,把它傳給introspection端點驗證,收到身份信息及包含的聲明。好了,請求帶着認證信息流向了Web API,全局特性AuthroizeAttribute
約束知足了,具體的API成功調用。
如今JS應用能夠登陸,能夠調用受保護的API了。可是,令牌一旦過時,受保護的API又用不了啦。
好消息是,oidc-token-manager
能夠配置成在令牌過時前來自動更新訪問令牌,無需用戶介入。
首先咱們來看看如何讓令牌過時,咱們必須縮短過時時間,過時時間是基於客戶端的一個設置項,咱們編輯IdentityServer中的Clients
類。
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { Enabled = true, ClientName = "JS Client", ClientId = "js", Flow = Flows.Implicit, RedirectUris = new List<string> { "http://localhost:56668/popup.html" }, AllowedCorsOrigins = new List<string> { "http://localhost:56668" }, AllowAccessToAllScopes = true, AccessTokenLifetime = 10 } }; } }
訪問令牌過時時間默認是1小時,咱們把它改爲10秒。
如今你登錄JS應用後,過10秒鐘在訪問API,你又會獲得401未受權錯誤啦。
咱們將依賴oidc-client-js
幫咱們自動更新令牌
在oidc-client-js
內部會記錄訪問令牌的過時時間,並在過時前向IdentityServer發送受權請求來獲取新的訪問令牌。按照prompt
設置 --默認設置爲none, 在會話有效期內,用戶不須要從新受權來獲得訪問令牌--,這些動做是用戶不可見的。IdentityServer會返回一個新的訪問令牌替代即將過時的舊令牌。
下面是訪問令牌過時和更新的設置說明:
accessTokenExpiring
事件在過時前會激發accessTokenExpiringNotificationTime
用來調整accessTokenExpiring
激發時間.默認是過時前60
秒。automaticSilentRenew
,用來在令牌過時前自動更新令牌。silent_redirect_uri
是指獲得新令牌後須要重定向到的URL。oidc-client-js
更新令牌的大體步驟以下:
當令牌快過時的時候,oidc-client-js
會建立一個不可見的iframe
,並在其中啓動要給新的受權請求,若是請求成功,identityServer會讓iframe重定向到silent_redirect_uri
指定的URL,這部分的的JS代碼會自動更新全局用戶信息,這樣主窗口就能夠獲得更新後的令牌。
理論講完了,咱們如今來按照上述內容改代碼:
var settings = { authority: 'https://localhost:44300', client_id: 'js', popup_redirect_uri: 'http://localhost:56668/popup.html', // Add the slient renew redirect URL silent_redirect_uri: 'http://localhost:56668/silent-renew.html' response_type: 'id_token token', scope: 'openid profile email api', // Add expiration nofitication time accessTokenExpiringNotificationTime: 4, // Setup to renew token access automatically automaticSilentRenew: true, filterProtocolClaims: true };
silent_redirect_uri
須要一個頁面來處理更新用戶信息,代碼以下:
<!DOCTYPE html> <html> <head> <title></title> <meta charset="utf-8" /> </head> <body> <script src="node_modules/oidc-client/dist/oidc-client.js"></script> <script> new Oidc.UserManager().signinSilentCallback(); </script> </body> </html>
如今須要告訴IdentityServer,新的重定向地址也是合法的。
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { Enabled = true, ClientName = "JS Client", ClientId = "js", Flow = Flows.Implicit, RedirectUris = new List<string> { "http://localhost:56668/popup.html", // The new page is a valid redirect page after login "http://localhost:56668/silent-renew.html" }, AllowedCorsOrigins = new List<string> { "http://localhost:56668" }, AllowAccessToAllScopes = true, AccessTokenLifetime = 70 } }; } }
當更新成功,UserManager
會觸發一個userLoaded
事件,由於咱們在前面已經寫好了事件處理器,更新的數據會自動顯示在UI上。
當失敗的時候,silentRenewError
事件會觸發,咱們能夠訂閱這個事件來了解具體什麼錯了。
manager.events.addSilentRenewError(function (error) { console.error('error while renewing the access token', error); });
咱們把訪問令牌生存期設置爲10秒,並告訴oidc-client-js
過時前4秒更新令牌。
如今登錄之後,每6秒會向identityserver請求更新訪問令牌一次。
前端程序的登出和服務端程序的登出不同,好比,你在瀏覽器裏刷新頁面,訪問令牌就丟失了,你須要從新登錄。可是當登錄彈出框打開時,它發現你還有一個IdentityServer的有效會話Cookie,因此它不會問你要用戶名密碼,反而馬上關閉本身。整個過程和自動後臺更新令牌差很少。
真正的登出意味着從IdentityServer登出,下次進入由IdentityServer保護的程序時,必須從新輸入用戶名密碼。
過程不復雜,咱們只須要在登出
按鈕事件裏面調用UserManager
的signoutRedirect
方法,固然,咱們也須要在IdentityServer
註冊登出重定向url:
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { Enabled = true, ClientName = "JS Client", ClientId = "js", Flow = Flows.Implicit, RedirectUris = new List<string> { "http://localhost:56668/popup.html", "http://localhost:56668/silent-renew.html" }, // Valid URLs after logging out PostLogoutRedirectUris = new List<string> { "http://localhost:56668/index.html" }, AllowedCorsOrigins = new List<string> { "http://localhost:56668" }, AllowAccessToAllScopes = true, AccessTokenLifetime = 70 } }; }
[...] <div class="row"> <div class="col-xs-12"> <ul class="list-inline list-unstyled requests"> <li><a href="index.html" class="btn btn-primary">Home</a></li> <li><button type="button" class="btn btn-default js-login">Login</button></li> <li><button type="button" class="btn btn-default js-call-api">Call API</button></li> <!-- New logout button --> <li><button type="button" class="btn btn-danger js-logout">Logout</button></li> </ul> </div> </div>
var settings = { authority: 'https://localhost:44300', client_id: 'js', popup_redirect_uri: 'http://localhost:56668/popup.html', silent_redirect_uri: 'http://localhost:56668/silent-renew.html', // Add the post logout redirect URL post_logout_redirect_uri: 'http://localhost:56668/index.html', response_type: 'id_token token', scope: 'openid profile email api', accessTokenExpiringNotificationTime: 4, automaticSilentRenew: true, filterProtocolClaims: true }; [...] $('.js-logout').on('click', function () { manager .signoutRedirect() .catch(function (error) { console.error('error while signing out user', error); }); });
當點擊logout
按鈕時,用戶會重定向到IdentityServer,因此回話cookie會被清除。
注意,上面圖片顯示的是IdentityServer的頁面,不是JS應用的界面 上面的例子是經過主頁面登出,oidc-client-js
提供了一種在彈出框中登出的方式,和登陸差很少,具體的信息能夠參考 oidc-client-js
的文檔.
JS應用的會話開始於咱們從IdentityServer獲得有效的身份令牌。IdentityServer自身也要維護一個會話管理,在響應受權請求的時候會返回一個session_state
。關於OpenID Connect詳細規格說明,請參看這裏.
有些狀況下,咱們想知道用戶是否結束了IdentityServer上的回話,好比說,在另一個應用程序中登出引發在IdentityServer上登出。檢查的方式是計算 session_state
的值. 若是它和IdentityServer發出來的同樣,那麼說明用戶還處於登錄狀態。若是變化了,用戶就有可能已經登出了,這時候建議啓動一次後臺登錄請求(帶上prompt=none
).若是成功,咱們會獲得一個新的身份令牌,也說明在IdentityServer上,用戶仍是處於登錄狀態。失敗了,則說明用戶已經登出了,咱們須要讓用戶從新登錄。
不幸的是,JS應用本身沒辦法計算session_state
的值,由於session_state
是IdentityServer的cookie,咱們的JS應用沒法訪問。OpenID的規格 要求裝載一個不可見的iframe
調用IdentityServer的checksession端點。JS應用和iframe
能夠經過postMessage
API通訊.
這個端點監聽來自postMessage
的消息,按要求提供一個簡單的頁面。傳送到端點的數據用來計算會話的哈希值。若是和IdentityServer上的同樣,這個頁面返回unchanged
值,不然返回changed
值。若是出現錯誤,則返回error
.
好消息是oidc-client-js
啥都會 O(∩_∩)O.
事實上,默認設置就會監視會話狀態。
相關的屬性是 monitorSession
.
當用戶一登錄進來,oidc-clieng-js
就會建立一個不可見的iframe
,這個iframe
會裝載identityserver的會話檢查端點。
每隔一段時間,這個iframe
都會發送client id 和會話狀態給IdentityServer,並檢查收到的結果來斷定會話是否已經改變。
咱們能夠利用oidc-client-js
的日誌系統來認識整個過程是如何進行的。默認狀況下oidc-client-js
配置的是無操做(no-op)日誌記錄器,咱們能夠簡單的讓它輸出到瀏覽器控制檯。
Oidc.Log.logger = console;
爲了減小日誌量,咱們增長訪問令牌的生存期。
更新令牌會產生大量日誌,如今的設置沒6秒要來一次,咱們都沒有時間來詳細檢查日誌。因此咱們把它改爲1分鐘。
public static class Clients { public static IEnumerable<Client> Get() { return new[] { new Client { Enabled = true, ClientName = "JS Client", ClientId = "js", Flow = Flows.Implicit, RedirectUris = new List<string> { "http://localhost:56668/popup.html", "http://localhost:56668/silent-renew.html" }, PostLogoutRedirectUris = new List<string> { "http://localhost:56668/index.html" }, AllowedCorsOrigins = new List<string> { "http://localhost:56668" }, AllowAccessToAllScopes = true, // Access token lifetime increased to 1 minute AccessTokenLifetime = 60 } }; }
最後,當用戶會話已經改變,自動登陸也沒成功。 UserManager
會觸發一個userSinedOut
事件,如今讓咱們來處理這個事件。
manager.events.addUserSignedOut(function () { alert('The user has signed out'); });
如今從新回到JS應用,登出,打開瀏覽器控制檯,從新登錄; 你會發現每隔2秒鐘(默認設置)--oidc-client-js
會檢查會話是否仍是有效。
如今咱們來證實它按照咱們設想的那樣工做,咱們打開一個新的瀏覽器tab,轉到JS應用並登錄。如今這兩個tab都在檢查會話狀態。從其中要給tab登出,你會看到另一個tab會顯示以下窗口:
做者:滅蒙鳥連接:http://www.jianshu.com/p/fde63052a3a5來源:簡書著做權歸做者全部。商業轉載請聯繫做者得到受權,非商業轉載請註明出處。