关于spring cloud OAuth2
OAuth2是一个基于令牌的安全框架,允许用户使用第三方验证服务进行验证,如果用户成功通过了验证,则会获得一个令牌,该令牌必须与每个请求一起发送,然后验证服务对每次请求的令牌进行验证,确定这个令牌是否有权限访问。
OAuth2将安全性分解为4个部分:
- 受保护资源:这是开发人员想要保护的资源(在这里就是一个个微服务接口),需要确保通过验证并且具有访问权限的用户才能访问他
- 资源所有者:就是哪些用户可以访问该服务,以及他们可以使用该服务完成哪些事情
- 应用程序:这是代表用户调用服务的应用程序,毕竟用户是很少直接调用服务的,依赖应用程序为他们服务。
- OAuth2验证服务器:是应用程序和保护资源之间的中间人,做身份的验证和授权
在我们微服务框架中,为了保证微服务的对外安全,一般都会要为微服务接口做权限校验。这里spring为我们提供了开箱即用的OAuth2和Security。我们用代码简单的模拟一下。
搭建OAuth2微服务授权应用
这里我们先创建一个spring boot服务,作为OAuth2的验证服务。
- 创建OAuth2服务,添加maven依赖
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
添加OAuth2和security依赖的jar
- 在启动类上添加
@EnableAuthorizationServer
和@EnableResourceServer
注解告诉spring boot这是一个OAuth2服务和受保护的资源。并且添加一个/user
的端口,此端口由受保护服务调用,验证访问令牌和用户角色。
@SpringBootApplication
@RestController
@EnableResourceServer
@EnableAuthorizationServer
public class SecuitryApplication {
@RequestMapping(value = "/user", produces = "application/json")
public Map<String, Object> user(OAuth2Authentication user) {
Map<String, Object> userInfo = new HashMap<>();
userInfo.put("user", user.getUserAuthentication().getPrincipal());
userInfo.put("authorities", AuthorityUtils.authorityListToSet(user.getUserAuthentication().getAuthorities()));
return userInfo;
}
public static void main(String[] args) {
SpringApplication.run(SecuitryApplication.class, args);
}
}
- 哪些服务可以使用服务
@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter{
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private UserDetailsService userDetailsService;
/**
* 定义通过验证服务注册了哪些客户端应用程序
* ClientDetailsServiceConfigurer 支持两种不同类型的存储:内存存储和JDBC存储
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory()
.withClient("security")
.secret("hui") // 注册应用程序的名称和秘钥
.authorizedGrantTypes("refresh_token", "password", "client_credentials") // 授权类型,密码,客户端凭证
.scopes("webclient", "mobileclient"); //客户端操作的范围
}
/**
* 使用默认的验证管理器和用户详细信息服务
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
}
这里定义了OAuth2Config
类,扩展了AuthorizationServerConfigurerAdapter
类,基本都是用了默认配置
- 定义用户ID 密码和角色
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
@Bean
protected UserDetailsService userDetailsService() {
return super.userDetailsService();
}
/**
* 定义用户名 密码和角色
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("hui.wang").password("hui.wang").roles("USER")
.and()
.withUser("admin").password("admin").roles("USER", "ADMIN");
}
}
这里也基本都是用了默认配置,仅仅定义了用户和角色
- 配置application文件
spring:
application:
name: security-server
server:
port: 9090
context-path: /auth
eureka:
instance:
prefer-ip-address: true #注册服务的IP
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
register-with-eureka: true
配置了context-path和注册eureka
-
启动服务,然后使用Post man来验证
登录1
登录2
可以看到返回值:
{
"access_token": "3ca13458-6e6f-48b9-a7c9-13f329ca68ca",
"token_type": "bearer",
"refresh_token": "0635cc7f-521e-429b-99c2-37861d8c44c7",
"expires_in": 43199,
"scope": "webclient"
}
其中access_token
是关键字段,调用收保护的资源必须携带的令牌
使用OAuth服务
- consumer端和provider端都要添加maven
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-jwt</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-rsa</artifactId>
</dependency>
- consumer端和provider端都要添加OAuth2的服务地址,在application中配置
security:
oauth2:
resource:
userInfoUri: http://localhost:9090/auth/user
- provider端配置为受保护的资源,添加
@EnableResourceServer
注解
@SpringBootApplication
@EnableDiscoveryClient
@EnableResourceServer
public class ProviderApplicatioin {
public static void main(String[] args) {
SpringApplication.run(ProviderApplicatioin.class, args);
}
}
- provider端配置访问权限
@Configuration
public class ResourceServerConfig extends ResourceServerConfigurerAdapter{
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated();
}
}
- consumer 配置OAuth2RestTemplate,保证令牌可以传递给provider端
@SpringBootApplication
@EnableDiscoveryClient
@EnableResourceServer
public class ConsumerApplication {
@Bean
public OAuth2RestTemplate auth2RestTemplate(OAuth2ClientContext oauth2ClientContext,
OAuth2ProtectedResourceDetails details) {
return new OAuth2RestTemplate(details, oauth2ClientContext);
}
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
这个时候调用consumer端服务的时候需要在header里面添加Authorization
字段,值为字符串Bearer
+ access_token
中间有一个空格
网友评论