1. 程式人生 > >asp.net core系列 58 IS4 基於瀏覽器的JavaScript客戶端應用程序

asp.net core系列 58 IS4 基於瀏覽器的JavaScript客戶端應用程序

登錄 程序 openid policy 密鑰 standards xmlhttp 客戶 alt

原文:asp.net core系列 58 IS4 基於瀏覽器的JavaScript客戶端應用程序

一. 概述

  本篇探討使用"基於瀏覽器的JavaScript客戶端應用程序"。與上篇實現功能一樣,只不過這篇使用JavaScript作為客戶端程序,而非core mvc的後臺代碼HttpClient實現。 功能一樣:用戶首先要登錄IdentityServer站點,再使用IdentityServer發出的訪問令牌調用We??b API,可以註銷IdentityServer站點下登錄的用戶,清除cookie中的令牌信息。所有這些都將來自瀏覽器中運行的JavaScript。

  此示例還是三個項目:

    IdentityServer令牌服務項目 http://localhost:5000

    API資源項目 http://localhost:5001

    JavaScript客戶端項目 http://localhost:5003

  開源Github

二. IdentityServer項目

  1.1 定義客戶端配置

    Config.cs中,定義客戶端,使用code 授權碼模式,即先登錄獲取code,再獲取token。項目其它處代碼不變。

       public static IEnumerable<Client> GetClients()
        {
            
return new List<Client> { // JavaScript Client new Client { ClientId = "js", ClientName = "JavaScript Client", //授權碼模式 AllowedGrantTypes = GrantTypes.Code,
//基於授權代碼的令牌是否需要驗證密鑰,默認為false RequirePkce = true, //令牌端點請求令牌時不需要客戶端密鑰 RequireClientSecret = false, RedirectUris = { "http://localhost:5003/callback.html" }, PostLogoutRedirectUris = { "http://localhost:5003/index.html" }, //指定跨域請求,讓IdentityServer接受這個指定網站的認證請求。 AllowedCorsOrigins = { "http://localhost:5003" }, AllowedScopes = { IdentityServerConstants.StandardScopes.OpenId, IdentityServerConstants.StandardScopes.Profile, "api1" } } }; }

    

三. API項目

  在Web API項目中配置 跨域資源共享CORS。這將允許從http:// localhost:5003 (javascript站點) 到http:// localhost:5001 (API站點) 進行Ajax調用(跨域)。項目其它處代碼不變。

       public void ConfigureServices(IServiceCollection services)
        {
            services.AddMvcCore()
                .AddAuthorization()
                .AddJsonFormatters();

            services.AddAuthentication("Bearer")
                .AddJwtBearer("Bearer", options =>
                {
                    options.Authority = "http://localhost:5000";
                    options.RequireHttpsMetadata = false;

                    options.Audience = "api1";
                });

            //添加Cors服務
            services.AddCors(options =>
            {
                // this defines a CORS policy called "default"
                options.AddPolicy("default", policy =>
                {
                    policy.WithOrigins("http://localhost:5003")
                        .AllowAnyHeader()
                        .AllowAnyMethod();
                });
            });
        }
        public void Configure(IApplicationBuilder app)
        {
            //添加管道
            app.UseCors("default");
            app.UseAuthentication();
            app.UseMvc();
        }

  

四. JavaScript客戶端項目

    在項目中,所有代碼都在wwwroot下,沒有涉及到服務端代碼,可以完全不用core程序來調用。目錄如下所示:

技術分享圖片

    其中添加了兩個html 頁(index.html, callback.html),一個app.js文件,這些屬於自定義文件。oidc-client.js是核心庫。

  4.1 index頁面

    用於調用登錄、註銷、和api。引用了oidc-client.js和app.js 

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

  

  4.2 app.js

    是應用程序的主要代碼,包括:登錄、Api請求,註銷。配置與服務端代碼差不多,如下所示:

/// <reference path="oidc-client.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:5000",
    client_id: "js",
    redirect_uri: "http://localhost:5003/callback.html",
    response_type: "code",
    scope:"openid profile api1",
    post_logout_redirect_uri : "http://localhost:5003/index.html",
};
//UserManager類
var mgr = new Oidc.UserManager(config);

//用戶是否登錄到JavaScript應用程序
mgr.getUser().then(function (user) {
    if (user) {
        log("User logged in", user.profile);
    }
    else {
        log("User not logged in");
    }
});

//登錄
function login() {
    mgr.signinRedirect();
}

//跨域請求api
function api() {
    mgr.getUser().then(function (user) {
        var url = "http://localhost:5001/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();
}

  4.3 callback.html

    用於完成與IdentityServer的OpenID Connect協議登錄握手。對應app.js中config對象下的redirect_uri: "http://localhost:5003/callback.html"。登錄完成後,我們可以將用戶重定向回主index.html頁面。添加此代碼以完成登錄過程

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

五 測試

  (1) 啟動IdentityServer程序http://localhost:5000

  (2) 啟動API程序http://localhost:5001。這二個程序屬於服務端

  (3) 啟動javascriptClient程序 http://localhost:5003

技術分享圖片

  (4) 用戶點擊login,開始握手授權,重定向到IdentityServer站點的登錄頁

技術分享圖片

  (5) 輸入用戶的用戶名和密碼,登錄成功。跳轉到IdentityServer站點consent同意頁面

技術分享圖片

  (6) 點擊 yes allow後,跳回到客戶端站點http://localhost:5003/index.html,完成了交互式身份認證。

技術分享圖片

  (7) 調用點擊Call API按鈕,獲取訪問令牌,請求受保護的api資源。調用CallAPI 時,是訪問的api站點http://localhost:5001/identity。

技術分享圖片

參考文獻

  添加JavaScript客戶端

asp.net core系列 58 IS4 基於瀏覽器的JavaScript客戶端應用程序