identityserver4-前后端分离的授权验证(代码片段)

lonelyxmas lonelyxmas     2023-02-16     784

关键词:

原文: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

 

htmlvue的微信授权登录前后端分离较为优雅的解决方案(代码片段)

查看详情

基于前后端分离的授权及认证(shiro-springboot-vue)(代码片段)

第一次写前后端分离的登录认证以及授权,写篇博客记录一下。登录认证前端,用户输入用户名密码,通过axios请求后端登录接口。后端通过SecurityUtils.getSubject()获取Subject对象,再根据传来的用户名、密码创建一... 查看详情

前后端分离shiro未执行授权方法解决办法(代码片段)

Shior简介ApacheShiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。使用Shiro的易于理解的API,您可以快速、轻松地获得任何应用程序,从最小的移动应用程序到最大的网络和企业应用程序。三个核心组件ÿ... 查看详情

spingsecurity前后端分离两种方案

前言本篇文章是基于SpringSecurity实现前后端分离登录认证及权限控制的实战,主要包括以下四方面内容:SpringSeciruty简单介绍;通过SpringSeciruty实现的基于表单和Token认证的两种认证方式;自定义实现RBAC的权限控制;跨域问题处理;S... 查看详情

前后端分离架构下的oauth2.0授权流程(代码片段)

前后端分离案例代码:spring-security-oauth2.0-sample关于OAuth2.0规范介绍请参考OAuth2.0Simplified关于OAuth2.1草案介绍请参考OAuth2.1用户点击前端开始第三方登录前端调用后端接口开始第三方登录后端组装完client_id,redirect_uri,response_... 查看详情

前后端分离项目中springboot集成shiro实现权限控制

文章目录​​使用注解控制鉴权授权​​​​使用url配置控制鉴权授权​​​​表结构​​​​jar包依赖​​​​代码说明​​​​身份认证​​​​权限认证​​​​跨域问题解决​​​​登录验证不进行重定向改为设置http... 查看详情

前后端分离实践

前后端分离并不是什么新鲜事,到处都是前后端分离的实践。然而一些历史项目在从一体化Web设计转向前后端分离的架构时,仍然不可避免的会遇到各种各样的问题。由于层出不穷的问题,甚至会有团队质疑,一体化好好的,为... 查看详情

springsecurity+jwt做前后端分离权限认证(代码片段)

...案列、有数据库、有源码,上一篇写的很细但是不是前后端分离,这一篇把前后端分离补上,数据库和Mapper模块都和前面的一致就不累述了,以下都是我自己的理解,如果什么地方有问题,请 查看详情

前后端分离

一、什么是前后端分离?最开始租内讨论的过程中我们发现。每个人对前后端分离的理解不一样。为了保证能在同一个频道讨论,先就什么是"前后端分离"达成一致大家一致认同的前后端分离的例子就是SPA,所有用到的展现的数据... 查看详情

前后端分离的好处有哪些?

前后端分离是什么?前后端分离的好处都有哪些?如果两者不分离,会带来什么麻烦事?针对网友关注度非常高的话题,我们今天来大家一一解答。一、什么是前后端分离?前后端分离实质上是前后端代码分离,一般后端人员主... 查看详情

前后端分离浅析

什么是前后端分离?前后端为什么要分离?前后端怎么样分离的?前后端分离给我们前端技术人员的开发带来什么样的好处?下面我就带着这些问题,来简单谈谈我了解到的前后端分离情况。 在讲前后端分离之前,让我们先... 查看详情

什么是前后端分离与前后端不分离

  我起初认为前后端分离是,在软件开发过程中前后端分工就叫做前后端分离,其实是前端所有用到的数据都是后端通过异步接口的方式提供的,前端只管页面的展示及效果。   前端和后端不分离的时候,前端的页面也... 查看详情

论前后端分离的好处

前后端分离最大的意义在于前后端可以并行开发。现在搞BS架构程序,前后端分离应该是主流了。前后端分离有什么好处呢?我认为最大的好处是,使得前后端可以并行开发。其次是前后端分离成2个不同的工种,... 查看详情

vue发布中的前后端分离和前后端不分离

前后端分离思路:前端和后台完全分离.前端提供静态的css和js,在运行时将css和js给后端,后端进行数据的请求(ajax)前后端分离就是前端和后台在不同的服务器上。基本是前端一个nginx加css和js后端nginx加index.html当用户访问的时候... 查看详情

前后端分离与不分离

前后端不分离   在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高。    这种应用模式比较适合纯网... 查看详情

django前后端不分离&前后端分离&模板引擎(代码片段)

一、前后端不分离与前后端分离的比较前后端不分离特点:后端需控制数据的展示前后端不分家,耦合严重返回的是HTML页面,适应性、拓展性差只能用于浏览器,其它终端不匹配前后端分离的特点:当前主流后端只对数据进行... 查看详情

前后端分离与前后端不分离

前后端不分离  在前后端不分离的应用模式中,前端页面看到的效果都是由后端控制的,由后端渲染页面或重定向,也就是后端需要控制前端的展示,前端与后端的耦合度很高。  这种应用模式比较适合纯网页应用,但是当... 查看详情

前后端分离的方法

网站前后端分离的方法  如何进行前后端分离:http://blog.csdn.net/github_26672553/article/details/51864112 https://segmentfault.com/q/1010000004494530解释了前后端的分离方法http://www.csdn.net/article/2015-10-25/2826033& 查看详情