OAuth2介绍与使用
来自一个小伙伴在微信上的提问:
看到这个问题,松哥忽然想到我自己之前写过 Spring Boot+Swagger 的用法:
也写过 OAuth2 + Jwt 的用法:
但是还没有将这两个结合在一起写过,所以小伙伴们对此有了疑问,想一想这还是一个非常常见的问题,因为现在使用令牌登录的场景越来越多,在这种情况下,如果使用 Swagger 来测试接口,要怎么在请求头中携带 Token 呢?今天松哥就来和大家聊一聊。
如果小伙伴们没有看过松哥之前发的 OAuth2 系列文章,建议一定先看下(公众号江南一点雨后台回复 OAuth2 获取),再来看本文内容,否则接下来的内容可能会犯迷糊。
这里松哥搭建一个 OAuth2+JWT 的环境来做演示。一共搭建两个服务:
服务名 端口 备注 auth-server 8080 授权服务器 user-server 8081 资源服务器
我稍微解释一下:
OK,这是我们项目的一个大致规划。
接下来我们来搭建 OAuth2 测试环境。
首先我们搭建一个名为 auth-server 的授权服务,搭建的时候,选择如下三个依赖:
项目创建完成后,首先提供一个 Spring Security 的基本配置:
在这段代码中,为了代码简洁,我就不把 Spring Security 用户存到数据库中去了,直接存在内存中。
这里我创建了一个名为 sang 的用户,密码是 123,角色是 admin。同时我还配置了一个表单登录。
这段配置的目的,实际上就是配置用户。例如你想用微信登录第三方网站,在这个过程中,你得先登录微信,登录微信就要你的用户名/密码信息,那么我们在这里配置的,其实就是用户的用户名/密码/角色信息。
需要注意的是,在当前案例中,我将采用 OAuth2 中的 password 模式进行登录,因此这里还需要明确的提供一个 AuthenticationManager 的 Bean。
基本的用户信息配置完成后,接下来我们来配置授权服务器。
首先来配置 TokenStore:
接下来对授权服务器进行详细配置:
这段代码有点长,我来给大家挨个解释:
好了,如此之后,我们的授权服务器就算是配置完成了,接下来我们启动授权服务器。
如果小伙伴们对于上面的配置感到迷糊,可以在公众号后台回复 OAuth2,先系统的学习一下松哥的 OAuth2 教程。
接下来我们搭建一个资源服务器。大家网上看到的例子,资源服务器大多都是和授权服务器放在一起的,如果项目比较小的话,这样做是没问题的,但是如果是一个大项目,这种做法就不合适了。
资源服务器就是用来存放用户的资源,例如你在微信上的图像、openid 等信息,用户从授权服务器上拿到 access_token 之后,接下来就可以通过 access_token 来资源服务器请求数据。
我们创建一个新的 Spring Boot 项目,叫做 user-server ,作为我们的资源服务器,创建时,添加如下依赖:
项目创建成功之后,先把前面的 AccessTokenConfig 拷贝到资源服务器上,然后添加如下配置:
这段配置代码很简单,我简单的说一下:
接下来我们再来配置两个测试接口:
如此之后,我们的资源服务器就算配置成功了。
分别启动授权服务器和资源服务器,先访问授权服务器获取 access_token:
再利用拿到的 access_token 去访问资源服务器:
OK,测试没问题。
接下来,我们在 user-server 中加入 swagger 功能,首先我们加入 swagger 依赖:
这里加入的依赖有两个,一个用来生成接口数据,另一个 swagger-ui 用来做数据展示。
请求头加参数,这里给大家介绍两种,先来看第一种。
先配置一个 Docket 实例,如下:
这里的配置稍微有点长,我来给大家解释下:
配置完成后,我们还需要给 swagger-ui 放行,否则 swagger-ui 相关的静态资源会被 Spring Security 拦截下来:
配置完成后,重启 user-server,浏览器输入 http://localhost:8081/swagger-ui.html,结果如下:
大家可以看到,页面中多了一个 Authorize 按钮,点击该按钮,输入 Bearer ${token},如下:
输入完成后,点击 Authorize 按钮,完成认证,接下来,user-server 中的各种接口就可以直接调用测试了。
上面这种方式比较通用,不仅仅适用于 OAuth2,也适用于其他一些自定义的 token 登录方式。
但是这种方式需要开发者先通过其他途径获取到 access_token,有的人会觉得这样有点麻烦,那么有没有更好的办法呢?请看方式二。
认证方式二就是直接在 Swagger 中填入认证信息,这样就不用从外部去获取 access_token 了,效果如下:
我们来看下这个怎么配置。
由于 swagger 去请求 /oauth/token 接口会跨域,所以我们首先要修改 auth-server ,使之支持跨域:
主要是两方面的修改,首先是配置 CorsFilter,允许跨域,如下:
然后在 SecurityConfig 中开启跨域支持:
经过这两步的配置,服务端的跨域支持就开启了。
接下来我们在 user-server 中修改关于 Docket bean 的定义:
这段配置跟前面的类似,主要是 SecurityScheme 不同。这里采用了 OAuthBuilder 来构建,构建时即得配置 token 的获取地址。
好了,配置完成,重启 auth-server 和 user-server 进行测试。测试效果就是松哥前面给出的图片,不再赘述。
这种方式最大的好处就是不用通过其他途径获取 access_token,直接在 swagger-ui 页面输入 password 模式的认证参数即可。非常方便,仅限于 OAuth2 模式。
好了,今天就和小伙伴们介绍了在 Swagger 请求中,如何修改请求头的问题,感兴趣的小伙伴可以下来试试哦~
本文案例下载地址:https://github.com/lenve/spring-security-samples
好啦,小伙伴们如果觉得有收获,记得点个在看鼓励下松哥哦~
Spring Security+ OAuth+单点登录原理 笔记
目前市场上微服务之间涉及到相互调用的问题,在这个过程中为了验证安全性,需要采用鉴权方式进行管理。目前主流的鉴权方式有Apache Shiro和Spring Security,在这里暂且不讨论Apache Shiro和Spring Security孰优孰劣。本文只讲解Spring Security的集成方式。同时,采用了OAuth 2.0的管理方式,主要基于Token来实现鉴权过程。
Spring Cloud提供了对Spring Security的管理以及OAuth 2.0的集成,方便了我们进行整合使用。
核心组件:
Api调用管理,主启动类:
依赖的jar包,父工程:
核心工程:
引入spring-security-oauth2-autoconfigure
Spring Security OAuth 2.0验证工具:
Spring Boot与Spring Security的集成
Spring Cloud管理Spring Security工具:
Spring Cloud管理OAuth 2.0:
集成Redis及JDBC:
Spring Social工具包:
JWT工具:
API工程:引入核心工程
Spring Boot启动工具及AOP:
引入Spring Boot缓存工具:
资源服务是用来配置用户名密码及手机号验证码等相关的用户认证方式的资源过滤路径,以及静态资源路径和相关请求地址设置认证等功能。
认证服务是用来设置认证使用的方式,Redis/JWT等工具,以及客户端id(clientId)和客户端密钥(clientSecret),只有验证通过的clientId和clientSecret才能获取Token。
我们使用继承AuthorizationServerConfigurerAdapter的SsbAuthorizationServerConfig认证服务类:
设置认证方式:
过滤的静态资源文件:
设置登录页:/form/token地址
设置手机认证及静态资源放开权限:
我们可以正式使用Spring Security OAuth配置用户名和密码登录,也就是表单登录,Spring Security默认有Form登录和Basic登录,我们已经在SsbResourceServerConfig类的configure方法上通过http.formLogin()设置了表单登录
也就是用户名密码登录。其中Spring Security已经实现了表单登录的封装了,我们只需要设置登录成功之后返回的Token就行。我们创建一个继承SavedRequestAwareAuthenticationSuccessHandler的SsbAuthenticationSuccessHandler实现类:
设置OAuth Token:
加密工具:
这样就可以成功的返回Token给前端,因此我们必须放开/form/token请求地址,我们已经在SsbResourceServerConfig类的configure放开了,已经设置了处理成功的ssbAuthenticationSuccessHandler方法,失败处理的ssbAuthenticationFailureHandler处理过程:
我们接下来创建基于UserDetailsService的ApiUserDetailsService类,本来应该在这个类中查询从数据库中的认证信息,在这里没有从数据库查询,代码如下:
给与了admin、ROLE_USER权限
打开PostMan测试
Authorization选择Basic Auth
填写密钥:
密钥为
中设置的密钥
添加至Header
在Body中添加登录用户名、密码
发送请求,返回:
表示认证成功
首先配置Redis:
打开Redis:
创建四个使用的类:
(1)基于AbstractAuthenticationToken的SmsCodeAuthenticationToken
(2)基于AbstractAuthenticationProcessingFilter的SmsCodeAuthenticationFilter
(3)基于AuthenticationProvider的SmsCodeAuthenticationProvider
(4)基于SecurityConfigurerAdapter的SmsCodeAuthenticationSecurityConfig
通过在资源管理器里面SsbResourceServerConfig添加
手机验证码接入
SmsCodeAuthenticationToken类的代码如下:
SmsCodeAuthenticationFilter的代码如下:
添加认证逻辑
SmsCodeAuthenticationProvider的代码如下:
SmsCodeAuthenticationSecurityConfig的代码如下:
接下来在PostMan里面
其Authorization:
添加进Header:
其Body里面:
发起请求,控制台:
PostMan里面:
验证成功
改造一下SsbAuthorizationServerConfig类,添加Redis保存Token:
将RedisTokenStoreConfig新建一下:
在application.properties添加:
我们测试下:
Redis控制台:
已存储至Redis
改造一下SsbAuthorizationServerConfig
接着创建JwtTokenStoreConfig
并且需要创建一个基于Token Handler,添加Token用户信息:
设置一下application.properties:
测试一下
本文已经使用了Spring Security封装用户表单登录,我们需要使用手机号验证码登录只需要在此基础上集成编写即可
主要工作在SsbResourceServerConfig里面实现了
完成鉴权验证
Spring Cloud项目OAuth2授权验证终极必杀技
在现代的网站中,我们经常会遇到使用OAuth授权的情况,比如有一个比较小众的网站,需要用户登录,但是直接让用户注册就显得非常麻烦,用户可能因为这个原因而流失,那么该网站可以使用OAuth授权,借助于github或者其他的第三方网站的认证授权,来获取相关的用户信息,从而避免了用户注册的步骤。
当然,很可能在第三方网站上授权获得用户信息之后,还需要在本网站填写一些必要的信息进行绑定,比如手机号,用户名等等。
但是这比单纯的注册要方便太多了,也容易让用户接受。
今天,我们将要讲解一下OAuth 2.0授权框架的构成,希望大家能够喜欢。
在传统的CS模式的授权系统中,如果我们想要借助第三方系统来访问受限的资源,第三方系统需要获取到受限资源服务器的用户名和密码,才能进行对资源服务器的访问,很显然这个是非常不安全的。
在OAuth2中,我们是怎么做的呢?
我们先来看一下OAuth2中授权的流程图:
一般来说OAuth2中有4个角色。
resource owner: 代表的是资源的所有者,可以通过提供用户名密码或者其他方式来进行授权。通常来是一个人。
resource server:代表的是最终需要访问到资源的服务器。比如github授权之后获取到的用户信息。
client: 用来替代resource owner来进行交互的客户端。
authorization server: 用来进行授权的服务器,可以生成相应的Access Token。
整个流程是这样的:
Client向resource owner发起一个授权请求,resource owner输入相应的认证信息,将authorization grant返回给client。
client再将获取到的authorization grant请求授权服务器,并返回access token。
client然后就可以拿着这个access token去请求resource server,最后获取到受限资源。
为了安全起见,access token总是有过期时间的,那么如果token过期了怎么办呢?
具体的办法就是refresh Token :
我们看一下refresh token的流程图:
前面的A,B,C,D和之前的讲到的流程是一致的。
如果接下来访问资源的时候,access token过期了,那么client会再次向认证服务发出refresh token的请求。
然后认证服务器会再次返回新的access token.
上面我们讲到的模式中,Client会保存Authorization Grant信息,并通过这个信息来去授权服务器请求Access Token。
Client直接保存Authorization Grant信息,并和授权服务器进行通信,这对client会有一定的安全限制。
如果是在web环境中,client是借助user-agent(web浏览器)来进行访问的该如何处理呢?
这里向大家介绍一个Authorization Code模式。
Client通过User-Agent发起请求,并附带跳转链接。当提供了用户的授权认证信息之后,授权服务器返回的不是token而是authorization code,拿到这个code之后,client可以通过这个code来获取access Token或者refresh Token。
上面的授权流程图我们可以通过一个具体的例子来说明,resource owner就是我们要访问的资源。 Authorization Server是第三方的授权服务器,比如github的授权服务。而User-Agent就是浏览器。
好了,我们开始具体流程的讲解:
比如用户想获取www.flydean.com的信息,但是需要登录,这个时候就跳转到github的登录界面,我们输入github的用户名密码,github会返回一个Authorization Code到我们的服务器比如 www.flydean.com/?code=code, client拿到这个code之后,会去后台请求github,去验证这个code的合法性,如果code合法,则github会返回access token的信息,client后面就可以通过access token去github资源服务器资源了。
举一个具体的access token返回值的例子:
在上面我们讲到的几个模式中,client都需要直接和授权服务器进行通信,从而获取到access Token,有没有什么方式可以不需要client和授权服务器直接通信就可以得到access token呢?
接下来我们讲一下隐式授权。
上图就是一个隐式授权的例子,和Authorization Code模式不同的是,授权服务器返回的是一个access token片段,只有这个片段,我们是无法得到access token的。
这里我们需要额外请求一次client resource服务器,服务器将会返回一个script脚本,通过这个脚本,我们对access token片段进行解析,得到最终的access token。
这种模式一般出现在resource owner非常信任client的情况下。
我们先看一下流程图:
这种模式实际上相当于用户将密码交给client保管,由client使用保存好的用户名密码向授权服务器请求资源。
这种模式下,client本身是有一定的授权范围的,可以通过client认证授权,直接获取到授权服务器的access token。
上面讲的通用流程中,其实很多角色都可以合并的。
接下来我们具体讲解一下如何使用github的OAuth2进行授权。
要使用github的OAuth2,需要首先在github中进行OAuth服务的注册。
点击注册按钮,输入相应的信息,我们就可以完成注册了。
这里比较重要的就是callback url,我们会通过这个callback url来传递授权信息。
注册成功之后,你会得到一个Client ID和Client Secret。
github的授权步骤分为三个部分:
在这一部分中,我们需要跳转到github的授权页面:
上面是跳转页面的链接,这个链接可以接下面几个参数:
client_id: 必须的参数,是我们上面注册app得到的client id。
redirect_uri: 可选参数,如果不设定,则会使用注册的时候提供的callback uri。
login:可选参数,指定具体的认证用户名。
scope:github中权限的范围。
state: 是一个随机数,用来防止cross-site攻击。
allow_signup: 是否允许在认证的时候注册。
看一下跳转的页面:
当用户授权之后,就会调整到callback页面,并带上code:
应用程序拿到code之后,通过调用下面的请求来获取access token:
这个post请求需要带上client_id,client_secret,code这三个必须的参数,还可以带上两个可选的参数redirect_uri和state。
默认情况下,我们会获取到下面的响应信息:
有了access token之后,我们需要将token放到请求head中,去请求用户信息:
OAuth2是一个非常常用的协议,也非常的方便,主要目的就是可以使第三方服务器可以获得授权范围内的用户信息。希望大家能够喜欢。
本文作者:flydean程序那些事
本文链接:http://www.flydean.com/oauth-2-0-in-depth/
本文来源:flydean的博客
欢迎关注我的公众号:「程序那些事」最通俗的解读,最深刻的干货,最简洁的教程,众多你不知道的小技巧等你来发现!