天天看點

【One by One系列】IdentityServer4(五)建立JavaScript用戶端

按照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檔案的地方。空項目中不存這個目錄,是以需要建立這個目錄。

【One by One系列】IdentityServer4(五)建立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\   
           
【One by One系列】IdentityServer4(五)建立JavaScript用戶端

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

啟動内置伺服器,搭載靜态檔案

【One by One系列】IdentityServer4(五)建立JavaScript用戶端
【One by One系列】IdentityServer4(五)建立JavaScript用戶端

登入成功

【One by One系列】IdentityServer4(五)建立JavaScript用戶端

【One by One系列】IdentityServer4(五)建立JavaScript用戶端

登出登入

【One by One系列】IdentityServer4(五)建立JavaScript用戶端

參考連結

http://docs.identityserver.io/en/latest/quickstarts/4_javascript_client.html

作者:Garfield

同步更新至個人部落格:http://www.randyfield.cn/

本文版權歸作者所有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected]

微信公衆号

掃描下方二維碼關注個人微信公衆号,實時擷取更多幹貨

【One by One系列】IdentityServer4(五)建立JavaScript用戶端

同步更新至:http://www.randyfield.cn/

出處:http://www.cnblogs.com/RandyField/

本文版權歸作者和部落格園共有,未經許可禁止轉載,否則保留追究法律責任的權利,若有需要請聯系[email protected].