按照OAuth2.0的4種授權方式,接下來應該介紹隐藏式(implicit),與之對應的OpenId Connect Flow的Implicit Flow,但是IdentityServer4官方最新文檔沒有明言,隻是給了Adding a JavaScript client的章節,而且根據内部代碼實作,還是采用的授權碼,并沒有使用Implicit Flow保護SPA,雖然不知道原因,但是我們還是按照官方最新文檔的來介紹,在之前的文檔,一個版本号為relase的文檔,有Implicit Flow的介紹,感興趣的童鞋,可以讀一下,最新的文檔編号是latest,從應用的實際代碼比較,差别并不大,唯一的差别可能就是原理,但是不去抓包檢視相關封包,并無法感覺。
1.建立用戶端
這裡我們按照官方教程來,使用ASP.NET Core空項目,用内置伺服器來承載用戶端靜态檔案。
1.1 建立項目
md JavaScript
cd JavaScript
dotnet new web
dotnet sln add .\JavaScript\JavaScript.csproj
1.2 修改launchSettings.json
{
"profiles": {
"JavaScript": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "http://localhost:6003",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}
1.3 添加 ‘靜态檔案中間件’
該項目是為用戶端運作而設計的,我們隻需要ASP.NET Core提供構成我們的應用程式的靜态HTML和JavaScript檔案,靜态檔案中間件就是為此設計的。
注冊靜态檔案中間件,同時删除其他代碼。
Startup.Configure
public void Configure(IApplicationBuilder app)
{
app.UseDefaultFiles();
app.UseStaticFiles();
}
這個中間件現在将提供應用程式的~/wwwroot檔案夾中的靜态檔案。這是我們将放置HTML和JavaScript檔案的地方。空項目中不存這個目錄,是以需要建立這個目錄。

1.4 oidc-client library下載下傳
在上篇,我們使用了一個庫去處理OpenID Connect 協定,在JavaScript中,我們同樣需要類似的庫,隻不過現在需要這個庫能夠在JavaScript中使用且浏覽器運作(因為node.js是服務端),https://github.com/IdentityModel/oidc-client-js
我們用npm下載下傳
npm i oidc-client
copy .\node_modules\oidc-client\dist\* .\wwwroot\
1.5 添加html和js檔案
兩個html檔案和一個除上面的oidc-client之外的js檔案組成我們JavaScript應用(SPA)
- index.html
- callback.html
- app.js
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<button id="login">Login</button>
<button id="api">Call API</button>
<button id="logout">Logout</button>
<pre id="results"></pre>
<script src="oidc-client.js"></script>
<script src="app.js"></script>
</body>
</html>
3個登入按鈕,引入兩個js檔案
function log() {
document.getElementById('results').innerText = '';
Array.prototype.forEach.call(arguments, function (msg) {
if (msg instanceof Error) {
msg = "Error: " + msg.message;
}
else if (typeof msg !== 'string') {
msg = JSON.stringify(msg, null, 2);
}
document.getElementById('results').innerHTML += msg + '\r\n';
});
}
//register click event handlers to the three buttons
document.getElementById("login").addEventListener("click", login, false);
document.getElementById("api").addEventListener("click", api, false);
document.getElementById("logout").addEventListener("click", logout, false);
//UserManager from the oidc-client to manage the OpenID Connect protocol
var config = {
authority: "http://localhost:5001",
client_id: "js",
redirect_uri: "http://localhost:6003/callback.html",
response_type: "code",
scope: "openid profile api1",
post_logout_redirect_uri: "http://localhost:6003/index.html",
};
var mgr = new Oidc.UserManager(config);
/*
* UserManager provides a getUser API to know if the user is
* logged into the JavaScript application.
* It uses a JavaScript Promise to return the results asynchronously.
* The returned User object has a profile property which contains
* the claims for the user.
* Add this code to detect if the user is logged into
* the JavaScript application:
*/
mgr.getUser().then(function (user) {
if (user) {
log("User logged in", user.profile);
}
else {
log("User not logged in");
}
});
function login() {
mgr.signinRedirect();
}
function api() {
mgr.getUser().then(function (user) {
var url = "http://localhost:6001/api/identity";
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.onload = function () {
log(xhr.status, JSON.parse(xhr.responseText));
}
xhr.setRequestHeader("Authorization", "Bearer " + user.access_token);
xhr.send();
});
}
function logout() {
mgr.signoutRedirect();
}
- 對3個按鈕進行監聽,并觸發不同的事件:addEventListener
- 登入
- 退出
- 調用api
這個HTML檔案是使用者登入到IdentityServer後指定的redirect_uri頁面,它将與IdentityServer完成OpenID Connect協定的登入握手。此代碼全部由我們在app.js中使用的UserManager類提供。登入完成後,我們可以将使用者重定向回首頁面index.html。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title></title>
</head>
<body>
<script src="oidc-client.js"></script>
<script>
new Oidc.UserManager({response_mode:"query"}).signinRedirectCallback().then(function() {
window.location = "index.html";
}).catch(function(e) {
console.error(e);
});
</script>
</body>
</html>
2.在IdentityServer注冊用戶端
用戶端應用已經準備好,像其他的用戶端一樣,需要IdentityServer中添加用戶端
// JavaScript Client
new Client
{
ClientId = "js",
ClientName = "JavaScript Client",
// 注意看這裡,GrantTypes還是選擇的Code
// GrantTypes.Implicit,
AllowedGrantTypes = GrantTypes.Code,
RequireClientSecret = false,
RedirectUris = { "http://localhost:6003/callback.html" },
PostLogoutRedirectUris = { "http://localhost:6003/index.html" },
AllowedCorsOrigins = { "http://localhost:6003" },
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"api1"
}
}
3.允許ajax跨域調用webapi
這個就需要在webapi項目中增加跨域配置
Startup.ConfigureServices
services.AddCors(options =>
{
// this defines a CORS policy called "default"
options.AddPolicy("default", policy =>
{
policy.WithOrigins("http://localhost:6003")
.AllowAnyHeader()
.AllowAnyMethod();
});
});
添加CORS中間件
public void Configure(IApplicationBuilder app)
{
app.UseRouting();
app.UseCors("default");
// ...
}
更多跨域配置,參考官方文檔
4.測試
運作IdentityServer
cd .\IdentityServer\
dotnet run
運作webapi
cd .\webapi\
dotnet run
VS運作SPA
啟動内置伺服器,搭載靜态檔案
登入成功
登出登入
參考連結
http://docs.identityserver.io/en/latest/quickstarts/4_javascript_client.html
作者:Garfield
同步更新至個人部落格:http://www.randyfield.cn/
本文版權歸作者所有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected]
微信公衆号
掃描下方二維碼關注個人微信公衆号,實時擷取更多幹貨
同步更新至:http://www.randyfield.cn/
出處:http://www.cnblogs.com/RandyField/
本文版權歸作者和部落格園共有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected].