写在开篇
本改编课程基于《OAuth 2.0 Cookbook_Protect Your Web Applications using Spring Security-Packt Publishing(2017)》。这本书侧重通过一个个精简的小例子来学习,如何使用spring security和oauth2.0来保护你的资源,。
课程从第二章开始,在Chaptor2,我们将学习以下内容:
使用授权码模式(Authorization Code grant)保护资源
- 支持隐式授权模式(Implicit grant)
- 使用密码模式(Resource Owner Password Credentials grant type )
- 配置客户端证书授权模式(Client Credentials grant)
- 支持refresh tokens
- 使用一个关系数据库来保存tokens和客户信息
- 使用redis保存token
- 实现客户端注册过程
- 中途破坏Oauth 2.0 Provider
- 使用Gatling,通过共享数据库测试token的验证过程
本节为隐式模式的用例,该模式直接运行在浏览器上(例如Javascript 应用)。本例将允许客户端以资源所有者的名义通过OAuth2.0保护的api。
Getting ready
Java 8+maven
源码可从以下链接获取https://github.com/PacktPubli...
How to do it…
接下来的步骤将指导你使用Spring Security OAuth2 搭建一个授权中心和一个资源服务器:
1.使用Spring Initializr 新建一个Springboot工程,加入web
,security
依赖,本例使用的springboot版本为“1.5.4.RELEASE”。
2.打开pom.xml
,加入以下依赖:
org.springframework.security.oauth
spring-security-oauth2
3.打开application.properties
文件,输入:
security.user.name=adolfo
security.user.password=123
4.新建UserProfile类与UserController类,内容与《学习3》中一致,这个是获取资源的接口。
5.新建OAuth2ResourceServer类,内容与《学习3》中一致,这个是资源管理器配置。
6.新建OAuth2AuthorizationServer类,即配置授权中心,注意其中的不同之处:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter{
@Override
public void configure(ClientDetailsServiceConfigurer clients)throws Exception{
clients.inMemory()
.withClient("clientapp")
.secret("123456")
.redirectUris("http://localhost:9000/callback")
.authorizedGrantTypes("implicit")
.accessTokenValiditySeconds(120)
.scopes("read_profile","read_contacts");
}
}
7.至此,我们已经完成了所有步骤,可以看出,在spring security框架中,授权码模式和隐式模式的构建模式很相似,仅仅在于配置授权中心时,设置不同的authorizedGrantTypes
。
How it works…
当我们使用@EnableAuthorizationServer
和@EnableResourceServer
这两个标签时,意味着,我们将Oauth 2.0的 endpoint加入到我们的项目中,与上一节的不同之处在于,我们使用了不同的授权模式,因此验证流程有一点点不同。此外,我们还必须知道的是,我们无需再往/oauth/token
发请求,因为我们现在是隐式模式。
接下来,我们来运行这个项目
1.首先,我们往授权中心发送如下请求:
http://localhost:8080/oauth/authorize?client_id=clientapp&redirect_uri=http://localhost:9000/callback&response_type=token&scope=read_profile&state=xyz
注意,此时response_type
的参数值为token
,而不是之前的code
。并且,我们的url没有使用编码,此处是作为教学用例所以省略,但在实际生产项目中,请记住要对所有参数进行编码。
当请求到达授权中心的endPoint后,授权中心将会要求资源所有者做身份验证
输入用户名密码后,将会跳到授权页面:
2.选择所需的scope
,点击Authorize
,你将跳回到之前设置的redirect uri
,正如你所见,回调路径携带了我们需要的access token
和之前输入的state
http://localhost:9000/callback#access_token=a68fce80-522f-43ee-85d4-6705c34 e555c&token_type=bearer&state=xyz&expires_in=119
除了access token
和state
,我们还得到了两个参数:token_type
和expires_in
。在上一节,使用授权码模式时,也获得了这些返回参数。重要的是要记住,隐式授权类型不允许按照OAuth2规范发布刷新令牌(refresh token)。这种行为是有必要的,它要求在使用运行在浏览器中的程序时,用户必须在场,这样可以在任何需要的时候,给第三方应用授权。
除此之外,授权中心有充分的能力来识别用户的session,避免重复要求资源中心来对客户端进行验证和授权。
隐式模式不允许发布refresh token的另一个理由是,隐式模式是应用在那些无法保护机密数据的公共应用,而这是refresh token要做的。
3.现在我们可以从api/profile
这个endpoint取回用户资料了,就像我们在上一节所做的,记住需携带access token,具体参见上一节。
There's more…
当使用隐式模式时,第三方应用始终需要通过重定向URI来注册,这样能确保不会将access token传给不需要验证的客户端。如果不这样做,一些心怀不轨的用户可能先注册一个应用,然后试图让其他的应用来顶替,接收这个access token,这样可能导致灾难性的结果。