IdentityServer4之Authorization Code(授权码)相对更安全
前言
接着授权模式聊,这次说说Authorization Code(授权码)模式,熟悉的微博接入、微信接入、QQ接入都是这种方式(这里说的是oauth2.0的授权码模式),从用户体验上来看,交互方式和Implicit没啥改变,随便找个网站瞅瞅,如慕课网(很不错的学习网站)的登录流程,见下图:
但其实在代码流程上是不太一样的,接下来边撸(我说的是敲代码)边聊。
正文
Authorization Code(授权码)模式比Implicit多了一个授权码的流程,即用户认证成功之后,授权服务器不会马上返回AccessToken,而是先返回一个code(这里称为授权码),然后客户端通过code再去获取Token,主要流程大概如下图:
流程说明:
- 用户通过浏览器(User-Agent)访问第三方客户端(Client);
- 如果客户端需要进行认证授权,则将其重定向到认证服务器(Authorization server);
- 用户(ResorceOwner)在认证服务器上进行认证;
- 认证服务器(Authorization server)验证成功之后,返回code(授权码);
- 客户端带上code(授权码)再去授权服务器请求获取AccessToken/IdToken;
- 授权服务器验证code(授权码)的有效性,验证成功后返回Token;
- 后续用户再操作客户端的时候,若需访问保护资源,直接在请求中带上AccessToken即可;
- 最终资源服务器(Resource server)返回对应信息;
术语解释:
- code(授权码):授权服务器认证成功之后返回的code,这个code有时效性,而且只能使用一次。
通过上面的流程,Authorization Code(授权码)模式其实更适合有后台的客户端,比如MVC程序,接收code和通过code获取Token的过程都在客户端后台进行,用户无感知;再加上code(授权码)的时效和次数限制,相对来说,这种模式是比较安全的。IdentityServer4已经封装好,所以撸码很简单,继续搞起来↓↓↓
1. 授权服务器和资源服务器代码先从上一节中拷贝过来;
-
对于资源服务器,还是不需要改动;
-
对于授权服务器,加个客户端完事;
2. 创建一个MVC客户端,引入相关包并配置OpenID Connect;
2.1 创建一个MVC项目,并引入对应的包,项目结构如下:
2.2 在Startup.cs文件中配置增加认证授权相关配置:
ConfigureServices方法中添加如下代码:
注,在访问API的时候,还需要加入:options.Scope.Add("orderApi"); 这个scope在授权服务器已经定义过的,之前的案例也有说到。
Configure方法中添加如下代码:
2.3 将客户端中Controller都增加[Authorize],表示将其保护起来,如果没有通过认证授权,就不能访问;
这样HomeController中的所有Action都保护起来了,如果需要访问,就需要先到授权服务器上进行认证授权。
3. 先跑起来看看效果,如果不出意外,应该没问题;
哦豁!翻车了
当在授权服务器认证授权完成之后,理当正常跳转到客户端(这里用到的是谷歌浏览器,版本为8x),但是偏偏某有,报了一个很莫名其妙的错,如下:
但通过吸取上一节Implicit的经验,初步认为是Cookies没在谷歌浏览器中写入成功,于是就换了360浏览器试了试,没毛病,一切如行云流水一般,正常跳转,原来是如下Cookie没有成功写入,所以找不到,在控制台的时候也有警告提示,没有找到Cookies;
MVC客户端控制台的提示:
解决措施
这是由于新版浏览器对Cookie策略的整改,而谷歌优先进行推广,所以测试总是在谷歌浏览器出问题;和上一节授权处理器的方式一样,如下:
在客户端中新增一个处理类:SameSiteCookiesServiceCollectionExtensions.cs,代码内容就不贴啦(git仓库里有),这是公开代码,大佬写好的解决方案;
写好处理类之后,直接使用即可,如下:
完成以上步骤,问题就解决啦;再去测试一把,果然没有问题;
注: 如果MVC客户端为Https的话就不会出现以上问题;这和SameSite
的三种模式有关:Strict
,Lax
,None
.这里留个小伙伴自己去扩充吧。
4. 在客户端中获取Claims信息及调用受保护的API资源;
先在导航菜单中增加获取Claims和调用API的按钮,因为用到的是MVC布局页,直接在_Layout.cshtml中复制粘贴就完事,如下:
4.1 获取Claims信息,代码如下:
根据导航菜单的配置,在HomeController中增加一个UserInfo的Action,并根据Action新增对应的视图文件UserInfo.csthml:
运行(启动授权服务->启动客户端),点击导航菜单UserInfo,如下:
4.2调用API(受保护资源)
在HomeController中增加一个CallAPI的Action,并根据Action新增对应的视图文件CallAPI.csthml,代码如下:
运行(启动授权服务->启动API资源服务->启动客户端),点击CallAPI菜单,如下:
到这Authorization Code(授权码)模式的简单使用就差不多啦,后续的内部业务鉴权在后续的实战项目中会说到; 细节流程留给小伙伴一步一步调试吧。
源码地址:https://github.com/zyq025/IDS4Demo/tree/main/AuthorizationCode。
总结
在编写测试Demo的时候,会出现很多细节的问题,所以建议小伙伴多敲敲代码,不要复制的那种;另外还需要注意新版本浏览器对Cookies的限制,可能导致一些莫名其妙的错误,上文中有已经处理;关于Cookies的规则,大家可以找找资料瞅瞅。目前所有的案例都是基于内存存储数据,在实际项目中肯定是需要将信息持久化的,所以下一篇说说IdentityServer4的持久化。
一个被程序搞丑的帅小伙,关注"Code综艺圈",跟我一起学~