写在开篇
本改编课程基于《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的验证过程
本例我们将学习如何配置密码模式,在实践中应该避免使用这种模式,因为这种模式客户端将拿到用户凭证,而这正是应该由Oauth 2.0通过access 代理来解决的事情。从用户凭证共享模式迁移到Oauth 2.0模式时,我们可以选择这种策略。当客户端与Oauth 2.0授权中心在同一solution下(充分信任客户端的情况下)时使用会较为安全。
Getting ready
Java8+maven
可以从https://github.com/PacktPubli... 下载项目源码,这个是书籍官方例子,亲自做过跑过,所以可以放心下载使用。
How to do it…
以下步骤将指导你,使用Spring Security OAuth2 配置一个授权中心和一个资源服务器:
1.使用Spring Initializr 新建一个Springboot工程,加入web
,security
依赖。
2.打开pom.xml,加入以下依赖:
org.springframework.security.oauth
spring-security-oauth2
3.打开application.properties文件,输入:
security.user.name = adolfosecurity.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("password")
.scopes("read_profile", "read_contacts");
}
}
7.与《学习3》唯一不同的就是authorizedGrantType
的设置,看上去和前两种模式的设置差不多,但是当你直接运行应用时就会报错:
{
"error": "unsupported_grant_type",
"error_description": "Unsupported grant type: password"
}
8.那是因为,密码模式需要在OAuth2AuthorizationServer
中配置AuthenticationManager
:
这是完整的OAuth2AuthorizationServer
类:
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends
AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints)
throws Exception {
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients)
throws Exception {
clients.inMemory()
.withClient("clientapp")
.secret("123456")
.authorizedGrantTypes("password")
.scopes("read_profile", "read_contacts");
}
}
现在,我们可以启动项目了
How it works…
当我们使用@EnableAuthorizationServer
和@EnableResourceServer
这两个注解时,已经通过spring security配置上oauth2.0的所有支持,正如前几个课程所示。最大的不同,是我们在OAuth2AuthorizationServer
中注入了authenticationManager
实例。我们之所以要使用这个实例是因为,授权中心在对第三方,携带access token的请求做出回应时,需要验证资源所有者的证书。
处理配置上的不同,在验证流程上也有所不同。在使用密码模式时,用户(或者称为资源所有者)必须发送凭证(用户名,密码),而这些操作将会在客户端的掌控下。因此,在使用这种模式与客户端和服务端交互时,需要资源所有者必须十分信任客户端。例如,你作为资源所有者与facebook的官方客户端交互,之后有转为与facebook的服务端做交互。
现在,我们来看看,如何使用密码模式来获取资源:
1.首先发送以下请求:
curl -X POST --user clientapp:123456 -H "accept: application/json" -H "content-type: application/x-www-formurlencoded" -d "grant_type=password&username=adolfo&password=123&scope=read_profile"
或者使用postman:
2.在上一步,我们拿到了access token,现在我们就可以使用这个token来获取资源了,注意,我们在之前没有设置token的过期时间,Spring Security OAuth2默认是43200s。我们应该根据授权模式的不同,设置不同的过期时间,例如隐式模式就应该使用短一些的过期时间。好了,现在我们来请求资源:
curl -X GET -H "authorization: Bearer 28405009-b53d-4e52-bfc3-c8889a477675"
There's more…
尽管我们建议尽量不要使用密码模式,但是如果当你交互的客户端与服务端(验证中心)都在一个范围内(公司/部门/名下)的时候,可以大胆使用。需要注意的是,客户端不应保留用户的用户名和密码。