上一篇文章咱们介绍了Asp.net core中身份验证的相关内容,并经过下图描述了身份验证及受权的流程:
注:改流程图进行过修改,第三方用户名密码登录后并非直接得到code/id_token/access_token,而是登陆后能够访问identityServer中受保护的资源(Authorize Endpoint),经过发起身份验证请求来实现受权码流程、隐式流程及混合流程来完成token的获取,它与直接经过用户名密码来获取token的Oauth2.0 Password GrantType方式是不同的。
在asp.net core应用程序中,经过受权码流程可使用第三方(IdentityServer)的用户名密码,通过一系列的token、userinfo获取,最后生成身份信息载体(Cookie),asp.net core应用程序使用cookie就能完成身份验证工做。这个过程对于用户来讲,它与通常的asp.net core应用程序(特指基于asp.net core identity的应用程序)是没有任何区别的,都是经过用户名密码登陆,而后就能够进入系统。对于应用程序来讲它仍然是基于cookie来完成身份验证,只不过生成cookie所需的数据是第三方提供的而已。
可是单页应用因为其特殊性,其UI渲染工做及业务逻辑的处理都是由浏览器完成,服务器不具有相关功能(仅需静态文件传输便可),其次单页应用会存在跨域问题,因此cookie就不适合做为单页应用的身份信息载体,本文就介绍如何使用jwt来完成单页应用的身份验证。
主要内容有:
- 建立一个简单的单页应用项目
- 使用单页应用完成受保护资源访问
- oidc Client简介
- oidc-client.js的各类用法
- 小结
建立一个简单的单页应用项目
一、新建一个asp.net core的web应用程序:
二、添加oidc的js组件:
能够经过npm进行安装或者在Github上直接下载,如下为npm安装方法:
npm i oidc-client
完成以后在相关目录下可找到oidc-client相关文件:
将其复制到适合的位置便可。
添加Client时须要注意几个关键信息:
- 受权类型支持受权码类型;
- 不须要客户端密码;
- 容许跨域,容许客户端跨域访问IdentityServer;
参考以下,内存实例:
数据库数据:
四、添加基于oidc-client的登陆、API访问以及登出业务逻辑代码App.js:
UserManager对象初始化:
使用UserManager实例进行登陆跳转:
使用UserManager实例获取用户信息,而后经过用户信息中的access token访问受保护资源:
使用UserManager实例进行登出跳转:
五、添加功能页面Index.html,包含登陆、API访问及登出功能:
六、添加用于处理受权码的重定向页面:
到此单页应用程序已经建立完毕,后面就使用该程序要介绍它是如何完成身份验证,并访问受保护资源的。
使用单页应用完成受保护资源访问
咱们使用一个简单的asp.net core web api项目(本系列文章用过的)来进行演示,它对于普通API项目来讲要点在于:
一、添加基于JwtBearer的身份验证处理器:
二、添加跨域处理,添加跨域策略配置:
三、在asp.net core应用请求管道中应用跨域配置:
四、受保护内容经过authorize特性进行标记:
一切准备就绪后运行三个应用程序,单页应用运行并打开index.html页面效果以下,一共有三个功能,登陆、调用API以及登出:
登陆:它其实是调用oidc Client的signinRedirect方法,语义上来讲它是经过重定向的方式进行登陆,而它实际执行的效果以下:
跳转到了IdentityServer的登陆页面,而后咱们再看看它本质上是作了什么?
为了可以看清楚整个请求过程,本例在callback.html页面加入了调试断点:
断点位于signinRedirectCallback方法以后,也就是完成回调处理以后(这个时候已经完成token等信息的获取),跳转到index.html页面以前。
如下是输入用户名密码提交后命中断点时的相关请求信息:
由上图能够看到,当输入用户名密码提交后(第一个请求),因为经过了身份验证,那么继续完成受权码流程(第二个请求),受权码流程完成后携带受权码重定向到Client配置的重定向地址(第三个请求).
第三个请求就到了咱们的callback.html页面,页面的加载首先请求了oidc-client.js文件,而后由UserManager的实例化以及signinRedirectCallback方法,来完成了后续请求,后续请求包含openid的配置信息请求、获取Token请求、获取用户信息(userinfo)请求以及检查会话请求。
以上一系列的请求结果就是在浏览器的会话存储中,咱们能够找到相关的数据信息:
断点经过后就来到了index.html页面,并打印出登陆用户信息:
点击Call API按钮后,程序将从存储信息中获取到access_token,携带access_token完成请求:
点击登出按钮后,程序将删除用户信息并跳转到IdentityServer的登出页面:
注:须要配置identityserver4的登出url:
oidc-client.js简介
前面的内容是基于oidc-client.js,即JavaScript版本的oidc客户端类库来实现的单页应用的,那么oidc-client.js到底为咱们提供了什么功能呢?
oidc-client.js是一个支持OIDC和Oauth2.0协议的JavaScript类库,除此以外它还提供用户会话和Token的管理功能。类库中的核心类型是UserManager,它提供了用户登陆、登出、用户信息管理等高层次的API,上面的例子中就是使用UserManager来完成的登陆、用户信息(Access Token)获取以及登出的。
oidc-client.js或者直接说UserManager使用上须要注意如下几个方面:
但这里要注意的是因为以上代码对用户是可见的,因此Client的密码就省略了。
- 方法:提供了用户管理、登陆、登出、以及相关回调方法,除此以外还有会话状态查询和开启/关闭静默刷新(token)的方法。登陆/登出分为三种类型:跳转、静默和弹出,具体如何使用后续介绍。

- 属性:能够返回UserManager的配置、事件以及元数据服务。
- 事件:UserManager包含了8个事件,如用户登陆/登出、access token过时等:

oidc-client.js的各类用法
弹出式登陆/登出
弹出式登陆/登出就是字面的意思,经过弹出窗口打开IdentityServer的登陆/登出页面完成相应功能。
下图为弹出式登陆(仅需调用UserManager的signinPopup方法便可):
注:回调页面须要使用signinPopupCallback:
下图为弹出式登出:
静默登陆与静默刷新
静默登陆和静默刷新指的就是signinSilent和startSilentRenew两个方法,并且须要注意的是startSilentRenew的原理其实是关注了accessTokenExpiring事件,当token即将过时时调用signinSilent进行静默登陆。
静默登陆方式又有两种其一是基于会话的,其二是基于刷新token,其中刷新token的优先级较高,换句话就是刷新token存在的时候,它就默认使用刷新token进行登陆,刷新token比较好理解,可是会话是什么呢?它实际上就是经过IdentityServer的登陆后所保持的状态,文章最开始的流程图中提到过,咱们之因此能够经过受权码流程进行受权是由于登陆以后有权访问IdentityServer受保护的受权终结点,从而能够获取受权码及相关Token,那这里的原理就是浏览器保存了登陆状态,因此能够再次访问受权终结点来获取并刷新Token信息。
基于会话的静默登陆,下图为点击静默登陆按钮后发起的请求信息,也就是正常的请求到受权码以后获取token及用户信息的过程:
须要注意的是回调页面须要使用signinSilentCallback方法,同时再也不须要页面跳转:
基于刷新token的静默登陆,在尝试刷新token登陆以前首先须要得到刷新token,oidc中刷新token的获取是须要client支持offline_access的scope,同时在发起获取token时携带该scope:
配置完成后从新登陆获取token便可在存储中找到刷新token信息 :
而后再次进行静默登陆(相应client须要支持refresh_token的受权方式):
静默登陆发起的请求信息:
响应信息中包含了新的token:
会话监听
会话监听是默认开启的,在正常登陆状态下,经过新的浏览器窗口从identityserver中登出(目的是清除identityserver存储在浏览器的会话信息):
信息清除后它会当即尝试发起新的身份验证请求,可是返回信息中包含“须要登陆”错误信息,能够在接收到相关错误信息时清除相关Token及用户信息,已达到单页应用随着IdentityServer会话结束而登出的效果:
小结
本篇文章介绍了单页应用使用IdentityServer进行身份验证的过程及oidc-client.js JavaScript类库在应用中的使用,oidc-client.js为咱们适配了oidc协议,同时还提供了丰富的功能和机制,使用这个类库能够大大减小实际工做中的开发量。
说到单页应用的身份验证,它最根本的机制无非就是得到Access Token和Refresh Token,使用Access Token做为身份信息载体来完成身份验证,使用Refresh Token做为更新Access Token的钥匙,经过保证Access Token不过时来保证用户可以正常访问相关资源。
但若是使用Oauth2.0协议来实现单页应用的登陆(Password受权模式)会存在一些问题,首先是单页应用对于受权服务器来讲是不可信的,可是Password受权由单页应用发起,属于受权服务器的用户信息及密码都要通过不可信的单页应用,这会形成一些安全问题,其次使用Oauth2.0协议完成受权后,应用与受权服务器之间实际上就没有任何关联了,受权服务器不保留用户会话,也没法实现用户登出联动的功能(即一方登出能够通知另外一方),这些也正是IdentityServer4或者说OIDC协议所处理的内容。
下篇文章,咱们将继续以IdentityServer4或者说OIDC的会话管理开始,深刻聊一聊它们的登陆与登出。
参考: