上两节介绍完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:\express\JavaScript_Client\node_modules\oidc-client\dist  有两个js文件

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

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

使用VSCode打开JavaScript_Client文件夹,在public(D:\express\JavaScript_Client\public)下新建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 + '\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: "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();
}

以下对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 + '\r\n';
});
}

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

IdentityServer4-前后端分离的授权验证(六)的更多相关文章

  1. SpringBoot2.0.3 + SpringSecurity5.0.6 + vue 前后端分离认证授权

    新项目引入安全控制 项目中新近添加了Spring Security安全组件,前期没怎么用过,加之新版本少有参考,踩坑四天,终完成初步解决方案.其实很简单,Spring Security5相比之前版本少 ...

  2. SpringBoot20 集成SpringSecurity02 -> 利用SpringSecurity进行前后端分离的登录验证

    1 SpirngBoot环境搭建 创建一个SpringBoot项目即可,详情参见三少的相关博文 参考博文 -> 点击前往 SpirngBoot项目脚手架 -> 点击前往 2 引入Spirn ...

  3. Django 利用JWT实现前后端分离的Token验证

    一.什么是Token? Token是服务端生成的一串字符串,以作客户端进行请求的一个令牌,当第一次登录后,服务器会生成一个Token并将此Token返回给客户端,以后客户端只需带上这个Token前来请 ...

  4. Spring Security OAuth2.0认证授权六:前后端分离下的登录授权

    历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...

  5. 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十六 ║Vue基础:ES6初体验 & 模块化编程

    缘起 昨天说到了<从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 十五 ║ Vue前篇:JS对象&字面量&this>,通过总体来看,好像大家对这一块不是很 ...

  6. 从壹开始前后端分离[.netCore 不定期 ] 36 ║解决JWT自定义中间件授权过期问题

    缘起 哈喽,老张的不定期更新的日常又开始了,在咱们的前后端分离的.net core 框架中,虽然已经实现了权限验证<框架之五 || Swagger的使用 3.3 JWT权限验证[修改]>, ...

  7. 解决Django+Vue前后端分离的跨域问题及关闭csrf验证

      前后端分离难免要接触到跨域问题,跨域的相关知识请参:跨域问题,解决之道   在Django和Vue前后端分离的时候也会遇到跨域的问题,因为刚刚接触Django还不太了解,今天花了好长的时间,查阅了 ...

  8. IdentityServer4之Implicit(隐式许可) —— oidc-client-js前后端分离

    IdentityServer4之Implicit(隐式许可) —— oidc-client-js前后端分离 参考 官方文档:oidc-client-js:oidc-client是一个JavaScrip ...

  9. SpringSecurity04 利用JPA和SpringSecurity实现前后端分离的认证和授权

    1 环境搭建 1.1 环境说明 JDK:1.8 MAVEN:3.5 SpringBoot:2.0.4 SpringSecurity:5.0.7 IDEA:2017.02旗舰版 1.2 环境搭建 创建一 ...

随机推荐

  1. mysql 案例~关于pt-osc工具的用途

    简介:今天咱们聊聊PT-OSC的东东一 简单介绍  1 标准组合   pt-online-schema-change --user= --password= --host= D=,t= --sock= ...

  2. 一步步使用Code::Blocks进行设置断点调试程序

    一.调试之前要做的工作 首先,我们要确保Code::Blocks的配置正确,调试工作才能进行得更顺利 为此,我们需要生成调试符号.调试符号可以让调试器知道代码的哪一行正在执行,这样你就可以知道程序运行 ...

  3. JAVA中的引用

    关于值类型和引用类型的话题,C++.JAVA.python.go.C#等等高级语言都有相关的概念,只要理解了其底层工作原理,可以说即使是不同的语言,在面试学习工作实践中都可以信手拈来(不要太纠集语言) ...

  4. C++11 多线程编程

    http://blog.csdn.net/column/details/ccia.html?&page=1

  5. 再谈:自定义结构体的对齐问题之__attribute__ ((packed))方法【转】

    转自:https://blog.csdn.net/ipromiseu/article/details/5955295 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.c ...

  6. Python3学习笔记23-StringIO和BytesIO

    StringIO 很多时候数据读取不一定是文件,也可以在内存中 StringIO顾名思义就是在内存中读写str 要把str写入StringIO,我们需要先创建一个StringIO,然后像文件一样写入即 ...

  7. Expm 4_2 有向无环图中的最短路径问题

    [问题描述] 建立一个从源点S到终点E的有向无环图,设计一个动态规划算法求出从S到E的最短路径值,并输出相应的最短路径. 解: package org.xiu68.exp.exp4; import j ...

  8. Jquery hover方法使用及 mouseenter与mouseleave和 mouseover与mouseout的区别

    定义和用法 hover() 方法规定当鼠标指针悬停在被选元素上时要运行的两个函数. jQuery 1.7 版本前该方法触发 mouseenter 和 mouseleave 事件. jQuery 1.8 ...

  9. 【前端】JS文本比较插件

    一.先上效果图 二.JS代码 /** * [文本比较插件] * 传递两个参数dom1.dom2,以dom1为基准进行比较. * 0)dom1和dom2不能都为空: * 1)如果dom1不存在,则dom ...

  10. OCM_第十五天课程:Section6 —》数据库性能调优 _SQL 访问建议 /SQL 性能分析器/配置基线模板/SQL 执行计划管理/实例限制

    注:本文为原著(其内容来自 腾科教育培训课堂).阅读本文注意事项如下: 1:所有文章的转载请标注本文出处. 2:本文非本人不得用于商业用途.违者将承当相应法律责任. 3:该系列文章目录列表: 一:&l ...