【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文件的地方。空項目中不存這個目錄,所以需要創建這個目錄。

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

index.html

<!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文件

app.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

callback.html

這個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

啟動內置服務器,搭載靜態文件

登錄成功

調用api

注銷登錄

參考鏈接

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


作者:Garfield

同步更新至個人博客:http://www.randyfield.cn/

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM