zoukankan      html  css  js  c++  java
  • IdentityServer4-前后端分离的授权验证(六)

           上两节介绍完Hybrid模式在MVC下的使用,包括验证从数据获取的User和Claim对MVC的身份授权。本节将介绍Implicit模式在JavaScript应用程序中的使用,使用Node.js+Express构建JavaScript客户端,实现前后端分离。本节授权服务和资源服务器基于第四和第五节。


    一、使用Node.js+Express搭建JavaScript客户端

          (1)首先需要Node.js环境

           下载并安装Node.js,官网下载地址:https://nodejs.org/en/ 

           输入指令:node –v  检测是否已安装Node.js,已安装会显示安装的Node.js版本

           

           (2)安装Express

           打开cmd,输入指令:npm install express-generator –g

           输入指令:express –h    已安装express会显示帮助文档

           

           (3)新建文件,创建JavaScript_Client应用程序

           新建文件夹(在D盘新建Express文件夹),cmd进入该文件夹。

           输入:express JavaScript_Client     在当前目录下创建一个名为JavaScript_Client的应用。目录结构如下:

           

           (4)安装依赖包

           输入:cd JavaScript_Client   进入JavaScript_Client目录

           输入:npm install   安装依赖包

           

           (5)启动并测试项目

           输入:npm start

           

           浏览器打开:http://localhost:3000 

           看到以下页面证明成功了。

           


    二、添加JavaScript客户端测试代码

          (1)安装oidc-client库

           输入:npm install oidc-client –save

           我们会发现在D:expressJavaScript_Client ode_modulesoidc-clientdist  有两个js文件

            

           我们只需使用这两个文件。把这两个文件复制到D:expressJavaScript_Clientpublic javascripts 目录下

          (2)添加测试用的HTML文件

           使用VSCode打开JavaScript_Client文件夹,在public(D:expressJavaScript_Clientpublic)下新建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=" javascripts/oidc-client.js"></script>
        <script src="app.js"></script>
    </body>
    </html> 

          (3)添加测试的js文件

           在public下新建app.js文件。

           黏贴以下代码

    /// <reference path=" javascripts/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: "id_token token",
        scope:"openid profile api1",
        post_logout_redirect_uri : "http://localhost:5003/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: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();
    }
    View Code

           以下对app.js代码进行分析

           App.js中log函数用来记录消息

    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 + '
    ';
        });
    }

           使用oidc-client库中的UserManager类来管理OpenID连接协议。添加此代码以配置和实例化UserManager:

    var config = {
        authority: "http://localhost:5000",
        client_id: "js",
        redirect_uri: "http://localhost:5003/callback.html",
        response_type: "id_token token",
        scope:"openid profile api1",
        post_logout_redirect_uri : "http://localhost:5003/index.html",
    };
    var mgr = new Oidc.UserManager(config);

           接下来,UserManager提供一个getUser API来获取用户是否登录到JavaScript应用程序。返回的User对象有一个profile属性,其中包含用户的声明。添加此代码以检测用户是否登录到JavaScript应用程序:

    mgr.getUser().then(function (user) {
        if (user) {
            log("User logged in", user.profile);
        }
        else {
            log("User not logged in");
        }
    });

           接下来,我们要实现登录、api和注销功能。UserManager提供登录用户的signinRedirect和用户登出的signoutRedirect。我们在上述代码中获得的用户对象还有一个access_token属性,可以使用该属性对web API进行身份验证。access_token将通过Bearer模式传递给Web API。添加以下代码在我们的应用程序中实现这三个功能:

    function login() {
        mgr.signinRedirect();
    }
    
    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)再新建一个callback.html。一旦用户登录到IdentityServer,这个HTML文件就是指定的redirect_uri页面。它将完成OpenID Connect协议与IdentityServer的登录握手。这里的代码都由我们前面使用的UserManager类提供。登录完成后,我们可以将用户重定向回index.html页面。添加此代码完成登录过程:

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8" />
        <title></title>
    </head>
    <body>
        <script src=" javascripts/oidc-client.js"></script>
        <script>
            new Oidc.UserManager().signinRedirectCallback().then(function () {
                window.location = "index.html";
            }).catch(function (e) {
                console.error(e);
            });
        </script>
    </body>
    </html>

           

          (8)修改服务端口为5003

           


    三、修改授权服务配置,资源服务器允许跨域调用API

          (1)修改授权服务配置

           在AuthServer项目,打开Config.cs文件,在GetClients中添加JavaScript客户端配置

                    // JavaScript Client
                    new Client
                    {
                        ClientId = "js",
                        ClientName = "JavaScript Client",
                        AllowedGrantTypes = GrantTypes.Implicit,
                        AllowAccessTokensViaBrowser = true,
    
                        RedirectUris = { "http://localhost:5003/callback.html" },
                        PostLogoutRedirectUris = { "http://localhost:5003/index.html" },
                        AllowedCorsOrigins = { "http://localhost:5003" },
    
                        AllowedScopes =
                        {
                            IdentityServerConstants.StandardScopes.OpenId,
                            IdentityServerConstants.StandardScopes.Profile,
                            "api1"
                        },
                    }

          (2)在资源服务配置允许跨域调用api

           在ResourceAPI项目,打开Startup.cs文件中的ConfigureServices方法,配置CORS,允许Ajax调用从http://localhost:5003调用http://localhost:5001的Web API。

     //JS-allow Ajax calls to be made from http://localhost:5003 to http://localhost:5001.
                services.AddCors(options =>
                {
                    //this defines a CORS policy called "default"
                    options.AddPolicy("default", policy =>
                    {
                        policy.WithOrigins("http://localhost:5003")
                            .AllowAnyHeader()
                            .AllowAnyMethod();
                    });
                });

           

           在Configure方法中将CORS中间件添加到管道中

     //JS-Add the CORS middleware to the pipeline in Configure:
    
                app.UseCors("default");

          (3)添加测试用的api接口

           添加IdentityController控制器

    [Route("[controller]")]
        public class IdentityController : ControllerBase
        {
            [Authorize(Roles ="admin")]
            [HttpGet]
            public IActionResult Get()
            {
                return new JsonResult(from c in User.Claims select new { c.Type, c.Value });
            }
        }

          (4)测试

           运行AuthServer项目,运行ResourceAPI项目。

           在VSCode终端输入:npm start

           

           打开浏览器:http://localhost:5003/

           

           点击Login,使用账号:zhubingjian 密码:123  登录

           

           登录返回用户的Claims信息

            

            点击Call API,调用资源服务器的API接口

           

           成功获取接口返回的信息。


           通过这六节的内容,大概地介绍了IdentityServer4中Client的应用场景,包括MVC、前后端分离和服务端。

           此外还介绍了如何动态配置Client、如何验证从数据库中获取的User以及自定义Claims的方法。

           这个系列对IdentityServer4的介绍也是我博客的起点,写博客虽然很花时间,但是可以帮助我加深对知识点的理解。然而文中也体现到我对某些知识点的理解还是不到位的,望大家见谅。

           参考官网地址:https://identityserver4.readthedocs.io/en/release/quickstarts/7_javascript_client.html

           授权服务和资源服务源码地址:https://github.com/Bingjian-Zhu/Mvc-HybridFlow.git

           JavaScript客户端源码地址:https://github.com/Bingjian-Zhu/Identity-JavaScript_Client.git

  • 相关阅读:
    《DSP using MATLAB》Problem 8.42
    《DSP using MATLAB》Problem 8.41
    《DSP using MATLAB》Problem 8.40
    《DSP using MATLAB》Problem 8.39
    IIR滤波器数字频带转换
    《DSP using MATLAB》Problem 8.38
    《DSP using MATLAB》Problem 8.37
    线性化①
    (七)根轨迹①
    (六)非零初始条件下的传递函数
  • 原文地址:https://www.cnblogs.com/FireworksEasyCool/p/10197620.html
Copyright © 2011-2022 走看看