Identity Server 4 從入門到落地(六)—— 簡單的單頁面客戶端


前面的部分:
Identity Server 4 從入門到落地(一)—— 從IdentityServer4.Admin開始
Identity Server 4 從入門到落地(二)—— 理解授權碼模式
Identity Server 4 從入門到落地(三)—— 創建Web客戶端
Identity Server 4 從入門到落地(四)—— 創建Web Api
Identity Server 4 從入門到落地(五)—— 使用Ajax 訪問 Web Api

認證服務和管理的github地址: https://github.com/zhenl/IDS4Admin
客戶端及web api示例代碼的github地址:https://github.com/zhenl/IDS4ClientDemo

前面我們在Web應用的頁面上使用Ajax訪問Web Api, 這種情況下,認證以及獲取Access Token還是在后台進行的,而真正的單頁面應用沒有后台的參與,web服務器只起到host文件的作用,這部分我們編寫簡單的單頁面應用,試驗一下單頁面訪問受認證保護的Web Api。

我們參考Identity Server 4的官網示例編寫這個單頁面應用,將其中的認證服務器改為我們本地運行的認證服務http://localhost:4010,Web Api使用前面編寫的簡單示例,地址為http://localhost:5153。在編寫之前,首先下載oidc的客戶端,可以從github下載: https://github.com/IdentityModel/oidc-client-js/releases/tag/1.11.5 。我們使用編譯完成的最終文件,將下載的文件解壓,dist目錄就是我們需要的文件。

首先使用Visual Studio 2022創建一個空的Asp.Net Core Web項目,我們使用這個項目作為html和js文件的宿主,除此之外不做其它工作。在項目目錄下創建wwwroot目錄,用於保存html和js文件,將下載的dist目錄拷貝到這個目錄中,目錄名字改為oidc-client-js-1.11.5。然后在wwwroot下創建index.html、callback.html和app.js三個文件,文件的內容在后面填寫。項目的結構如下:

然后修改lanuchSettings.json,項目的運行地址是http://localhost:5210:

{
  "profiles": {
    "IDS4ClientJS": {
      "commandName": "Project",
      "dotnetRunMessages": true,
      "launchBrowser": true,
      "applicationUrl": "http://localhost:5210",
      "environmentVariables": {
        "ASPNETCORE_ENVIRONMENT": "Development"
      }
    }
  }
}

接下來修改program.cs,使應用支持靜態文件:

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.UseDefaultFiles();
app.UseStaticFiles();
app.Run();

這樣修改后,項目將Index.html作為缺省頁面。
然后就是修改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-1.11.5/oidc-client.js"></script>
    <script src="app.js"></script>
</body>
</html>

內容很簡單,就是創建三個按鈕,分別是登錄、登出和調用Api。所實現的功能在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';
    });
}

document.getElementById("login").addEventListener("click", login, false);
document.getElementById("api").addEventListener("click", api, false);
document.getElementById("logout").addEventListener("click", logout, false);

var config = {
    authority: "http://localhost:4010",
    client_id: "js",
    redirect_uri: "http://localhost:5210/callback.html",
    response_type: "code",
    scope: "openid profile myapi",
    post_logout_redirect_uri: "http://localhost:5210/index.html",
};
var mgr = new Oidc.UserManager(config);

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:5153/WeatherForecast";

        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();
}

app.js使用oidc js客戶端中定義的Oidc.UserManager實現對認證服務器的訪問,完成認證和獲取access token的工作,其配置在config 中定義,

var config = {
    authority: "http://localhost:4010",
    client_id: "js",
    redirect_uri: "http://localhost:5210/callback.html",
    response_type: "code",
    scope: "openid profile myapi",
    post_logout_redirect_uri: "http://localhost:5210/index.html",
};

最后,定義callback.html:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <script src="oidc-client-js-1.11.5/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>

到此,客戶端編寫完成,我們還需要在認證服務管理中定義這個客戶端,注意,在定義時需要選擇單頁面應用:

參考上面config中的定義設置客戶端的其它部分:


最后一項工作是修改Web Api,增加這個網址的CORS設置:

builder.Services.AddCors(option => option.AddPolicy("cors",
     policy => policy.AllowAnyHeader()
     .AllowAnyMethod()
     .AllowCredentials()
     .WithOrigins(new[] { "https://localhost:7002", "http://localhost:5210" })));

好了,現在可以測試一下這個應用了,在Visual Studio中將解決方案的啟動項目設置為多項目啟動,同時啟動JSClient和Web Api項目:

按F5運行,界面如下:

點擊Login,會重定位到認證服務器的登錄界面,登錄完成后會顯示用戶的信息:

點擊Call Api,會訪問Web Api並顯示結果:

到此,單頁面客戶端完成。相關代碼可以從github下載: https://github.com/zhenl/IDS4ClientDemo


免責聲明!

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



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