Spring Security 模块化(认证授权服务+资源服务)
Spring Security 模块化(认证授权服务+资源服务)
在微服务的架构下,对单体应用的认证授权服务和资源服务需要进行拆分和模块化处理。
该内容基于上一篇:实战单体应用(认证授权服务+资源服务)
项目结构
主要是将整个Spring Security OAuth2
共用的配置写到security-common
中,这样后期使用非常方便,只需要创建普通Spring Web
项目,然后引用security-common
模块即可。
SpringSecurity-demo
---auth-demo
---resources-demo
---security-common
security-common
ResourceServerConfig
@Configuration
@EnableResourceServer
// 开启注解鉴权
@EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
@Bean
@Primary
public ResourceServerTokenServices tokenServices() {
// 如果资源服务和认证服务在一起可以使用 DefaultTokenServices 进行本地校验
// 使用远程服务请求授权服务器校验token,必须指定url,client_id,client_secret
RemoteTokenServices services = new RemoteTokenServices();
services.setCheckTokenEndpointUrl("http://127.0.0.1:3000/oauth/check_token");
services.setClientId("rcbb");
services.setClientSecret("rcbb");
return services;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources
// 验证令牌的服务
.tokenServices(tokenServices())
.stateless(true);
}
//配置资源服安全规则
@Override
public void configure(HttpSecurity http) throws Exception {
http
// 授权的请求
.authorizeRequests()
// 任何请求
.anyRequest()
// 需要身份认证
.authenticated()
.and().csrf().disable();
}
}
并且使用Spring
的自动装配,src/main/resources/META-INF/spring.factories
配置。
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cc.rcbb.springsecurity.demo.common.config.ResourceServerConfig
auth-demo
认证服务的主要几个配置AuthorizationServerConfig
、TokenConfig
、WebSecurityConfig
。
TokenConfig
TokenConfig
之前单体的时候没有单独配置,是因为默认就是使用内存存储令牌。单独拎出来是为了后续扩展。
@Configuration
public class TokenConfig {
@Bean
public TokenStore tokenStore() {
// 使用内存存储令牌(普通令牌)
return new InMemoryTokenStore();
}
}
AuthorizationServerConfig
主要内容是开放授权服远程检验token
。
因为认证授权服服务和资源服务分开了,所以token
无法共享,可以通过远程的方式校验Token
。
还有一种思路就是通过Redis
,只要认证授权服服务和资源服务是使用的是同一个Redis
,那么资源服务就可自己做校验,直接通过资源服务查询Redis
。
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private TokenStore tokenStore;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private ClientDetailsService clientDetailsService;
@Autowired
private AuthenticationManager authenticationManager;
//令牌管理服务
@Bean
public AuthorizationServerTokenServices tokenService() {
DefaultTokenServices service = new DefaultTokenServices();
// 客户端详情服务
service.setClientDetailsService(clientDetailsService);
// 支持刷新令牌
service.setSupportRefreshToken(true);
// 令牌存储策略
service.setTokenStore(tokenStore);
// 令牌默认有效期2小时
service.setAccessTokenValiditySeconds(7200);
// 刷新令牌默认有效期3天
service.setRefreshTokenValiditySeconds(259200);
return service;
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
// 基于内存便于测试,使用in-memory存储
clients.inMemory()
// client_id
.withClient("rcbb")
// 未加密
//.secret("secret")
// 加密
.secret(passwordEncoder.encode("rcbb"))
// 资源列表
//.resourceIds("res1")
// 该client允许的授权类型authorization_code,password,refresh_token,implicit,client_credentials
.authorizedGrantTypes("authorization_code", "password", "client_credentials", "implicit", "refresh_token")
// 允许的授权范围
.scopes("all", "ROLE_ADMIN", "ROLE_USER")
// false跳转到授权页面
//.autoApprove(false)
//加上验证回调地址
.redirectUris("http://rcbb.cc");
}
/**
* 配置令牌的访问端点和令牌服务
*
* @param endpoints the endpoints configurer
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// 配置认证管理器
endpoints.authenticationManager(authenticationManager)
.tokenServices(tokenService());
}
/**
* @Description: 用来配置令牌端点(Token Endpoint)的安全约束
* Token令牌默认是有签名的,并且资源服务需要验证这个签名,
* 因此呢,你需要使用一个对称的Key值,用来参与签名计算,
* 这个Key值存在于授权服务以及资源服务之中。
* 或者你可以使用非对称加密算法来对Token进行签名,
* Public Key公布在/oauth/token_key这个URL连接中,
* 默认的访问安全规则是"denyAll()",
* 即在默认的情况下它是关闭的,
* 你可以注入一个标准的 SpEL 表达式到 AuthorizationServerSecurityConfigurer 这个配置中来将它开启
* (例如使用"permitAll()"来开启可能比较合适,因为它是一个公共密钥)。
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security
// 开放获取token key(这个是做JWT的时候开放的!也就是资源服可以通过这个请求得到JWT加密的key,目前这里没什么用,可以不用配置)
.tokenKeyAccess("permitAll()")
// 开放远程token检查
.checkTokenAccess("permitAll()")
// 允许client使用form的方式进行authentication的授权
.allowFormAuthenticationForClients();
}
}
resources-demo
基本上资源服务就没什么内容了,核心配置直接引入security-common
模块即可。
现在就只剩资源UserController
了。
@RestController
@RequestMapping("/user")
public class UserController {
@PreAuthorize("hasAuthority('user_add')")
@PostMapping
public String save() {
return "save() success";
}
@PreAuthorize("hasAuthority('user_remove')")
@DeleteMapping
public String remove() {
return "remove() success";
}
@PreAuthorize("hasAuthority('user_update')")
@PutMapping
public String update() {
return "update() success";
}
@Secured("ROLE_ADMIN")
@GetMapping
public String list() {
return "list() success";
}
}
测试
启动auth-demo
和resources-demo
服务。
首先先通过账号密码获取token
。
然后再携带token
访问资源服务,需要注意是资源服务是另外一个服务。
测试成功。
- 10
- 0
-
分享