前言

接着授权模式聊,这次说说Authorization Code(授权码)模式,熟悉的微博接入、微信接入、QQ接入都是这种方式(这里说的是oauth2.0的授权码模式),从用户体验上来看,交互方式和Implicit没啥改变,随便找个网站瞅瞅,如慕课网(很不错的学习网站)的登录流程,见下图:

但其实在代码流程上是不太一样的,接下来边撸(我说的是敲代码)边聊。

正文

Authorization Code(授权码)模式比Implicit多了一个授权码的流程,即用户认证成功之后,授权服务器不会马上返回AccessToken,而是先返回一个code(这里称为授权码),然后客户端通过code再去获取Token,主要流程大概如下图:

流程说明:

  1. 用户通过浏览器(User-Agent)访问第三方客户端(Client);
  2. 如果客户端需要进行认证授权,则将其重定向到认证服务器(Authorization server);
  3. 用户(ResorceOwner)在认证服务器上进行认证;
  4. 认证服务器(Authorization server)验证成功之后,返回code(授权码)
  5. 客户端带上code(授权码)再去授权服务器请求获取AccessToken/IdToken;
  6. 授权服务器验证code(授权码)的有效性,验证成功后返回Token;
  7. 后续用户再操作客户端的时候,若需访问保护资源,直接在请求中带上AccessToken即可;
  8. 最终资源服务器(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综艺圈",跟我一起学~

IdentityServer4之Authorization Code(授权码)相对更安全的更多相关文章

  1. [转]OAuth 2.0 - Authorization Code授权方式详解

    本文转自:http://www.cnblogs.com/highend/archive/2012/07/06/oautn2_authorization_code.html I:OAuth 2.0 开发 ...

  2. OAuth 2.0 - Authorization Code授权方式详解

    I:OAuth 2.0 开发前期准备 天上不会自然掉馅饼让你轻松地去访问到人家资源服务器里面的用户数据资源,所以你需要做的前期开发准备工作就是把AppKey, AppSecret取到手 新浪获取传送门 ...

  3. Oauth2.0(五):Authorization Code 授权

    Authorization Code 方式适用于有自己的服务器的应用.之所以叫这个名字,是因为流程中引入了一个叫做 authorization code 的东西.这个东西是一个一次性的临时凭证,用来换 ...

  4. 微信支持的Authorization code授权模式(公众号开发)(开放平台资料中心中的代公众号发起网页授权)

    链接:https://blog.csdn.net/ASZJBGD/article/details/82838356 主要流程分为两步: 1.获取code 2.通过code换取accesstoken 流 ...

  5. OAuth2.0和企业内部统一登录,token验证方式,OAuth2.0的 Authorization code grant 和 Implicit grant区别

    统一登录是个很多应用系统都要考虑的问题,多个项目的话最好前期进行统一设计,否则后面改造兼容很麻烦: cas认证的方式:新公司都是老项目,用的是cas认证的方式,比较重而且依赖较多,winform的项目 ...

  6. OAuth 第三方登录授权码(authorization code)方式的小例子

    假如上面的网站A,可以通过GitHub账号登录: 下面以OAuth其中一种方式,授权码(authorization code)方式为例. 一.第三方登录的原理 所谓第三方登录,实质就是 OAuth 授 ...

  7. IdentityServer4系列 | 授权码模式

    一.前言 在上一篇关于简化模式中,通过客户端以浏览器的形式请求IdentityServer服务获取访问令牌,从而请求获取受保护的资源,但由于token携带在url中,安全性方面不能保证.因此,我们可以 ...

  8. IdentityServer4实现OAuth2.0四种模式之授权码模式

    接上一篇:IdentityServer4实现OAuth2.0四种模式之隐藏模式 授权码模式隐藏码模式最大不同是授权码模式不直接返回token,而是先返回一个授权码,然后再根据这个授权码去请求token ...

  9. OAuth 2.0 授权码请求

    关于OAuth 2.0,请参见下面这两篇文章(墙裂推荐): <OAuth 2.0> <Spring Security OAuth 2.0> 纸上得来终觉浅,绝知此事要躬行.理论 ...

随机推荐

  1. java 生成xml

    生成xml @Test public void parseApplicationConfigXML(){ try { SAXReader sax = new SAXReader(); Document ...

  2. PA防火墙抓包结果显示重传(re-transmission)

    问题起因: 部分内网服务器调用外网站点抓取图片时出现缓慢及超时现象. 由于是由内向外方向的访问,且通过的应用层设备只有防火墙:而且用其他网段测试机测试的时候发现并没有上述访问缓慢或超时. 从防火墙抓包 ...

  3. Vue.js到前端工程化

    b站视频地址:黑马程序员Vue.js到前端工程化(webpack打包,以及Vue-cli3和Element-UI的使用) vue学习系列 1.vue概述 2.vue基本使用 3.vue模板语法 4.指 ...

  4. 《Proxy系列专题》:代理模式(静态、JDK、CGLib)

    <Proxy系列专题>:代理模式(静态.JDK.CGLib)使用 现象:在如今互联网时代,项目的复杂度不断的提升,有些场景下需要一定的设计优化来支撑业务的扩展,如为了不改动原始类,但需要对 ...

  5. 年度账单h5 移动端兼容问题以及优化建议(vue)

    定时器 vue实例中定义timer多余,创建的定时器代码和销毁定时器的代码没有放在一起,通常很容易忘记去清理这个定时器,不容易维护:建议使用this.$once('hook:beforeDestory ...

  6. 【uva 120】Stacks of Flapjacks(算法效率--构造法+选择排序思想)

    题意:有N张正在锅里的一叠煎饼,每张都有一个数字,代表其大小.厨师每次可以选择一个数k,把从锅底开始数第k张上面的煎饼全部翻过来,即原来在上面的煎饼现在到了下面.要求设计一种方法使得所有煎饼按照从小到 ...

  7. python的threading的使用(join方法,多线程,锁threading.Lock和threading.Condition

    一.开启多线程方法一 import threading,time def write1(): for i in range(1,5): print('1') time.sleep(1) def wri ...

  8. java——继承、抽象方法

    基本上大量篇章都是为了解决重名造成的各种问题,如果所有名称都不会重名,那么其实不会有多大问题 父类与子类中的成员变量重名问题: 成员方法重名时如果调用方法: 继承中方法的覆盖重写: 继承中构造函数: ...

  9. aop详解与实战

    1. 什么是AOP aop:面向切面编程.采用横向机制. oop:面向对象编程.采用纵向机制. AOP,面向切面编程.就是通过某个切入点(比如方法开始.结束)向某个切面(被切的对象)切入环绕通知(需要 ...

  10. hash table

    Hash Table,叫做哈希表,也叫做散列表.概念:通过某种对应关系h,使得每一个元素和储存位置一一对应.这种对应关系称为哈希函数.它最大的优点就是插入.搜索和删除得很快(O(1)).碰撞(Coll ...