zoukankan      html  css  js  c++  java
  • 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 + '
    ';
        });
    }
    
    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客户端

  • 相关阅读:
    在JavaScript中对HTML进行反转义
    JavaScript 删除数组中的对象
    CSS中的before和:after伪元素深入理解
    关于css浮动的一点思考
    前端常见跨域解决方案(全)
    window.location对象详解
    51nod 1001 数组中和等于K的数对
    51nod 1002 数塔取数问题
    51nod 1015 水仙花数
    51nod 1080 两个数的平方和
  • 原文地址:https://www.cnblogs.com/MrHSR/p/10735033.html
Copyright © 2011-2022 走看看