Spring Security-33-权限配置分离

之前的权限配置中,遗留了一个问题,就是在我们公用模块的配置中,有如下的配置
image

这里这个 /user/register 的配置其实是调用方的url, 在我们的公用项目里面,并不知道这些路径,所以我们需要实现的功能就是,调用方去自己的项目里面配置他的权限,然后我们把这些配置集中起来加到 Spring Security 的配置中去,下面来看一下如何实现

基本思路

  1. 提供一个 AuthorizeConfigProvider 接口
  2. 权限模块的通用配置实现该接口,然后进行配置
  3. 其他应用也可以实现这个接口来自定义自己的配置
  4. 创建一个 AuthorizeConfigManager 来管理所有的 AuthorizeConfigProvider 实现类
  5. 最后统一加到 Spring Security 的配置中去

代码实现

按照上面的思路,首先是 AuthorizeConfigProvider 接口,这个是公用的,所以放到 core 项目里面,代码如下:

1
2
3
4
5
6
7
8
9
public interface AuthorizeConfigProvider {

/**
* 权限配置
*
* @param config
*/
void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
}

这里的参数其实是 .authorizeRequests() 方法的返回值

然后提供一个我们默认的实现,就是web环境和 app 环境中的一些通用的配置,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@Component
public class GlobalAuthorizeConfigProvider implements AuthorizeConfigProvider {

@Autowired
private SecurityProperties securityProperties;

@Override
public void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
config.antMatchers(
SecurityConstants.DEFAULT_UNAUTHENTICATION_URL,
SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE,
SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX + "/*",
securityProperties.getBrowser().getLoginPage(),
SecurityConstants.DEFAULT_SIGN_UP_URL,
securityProperties.getBrowser().getSignUpPage(),
SecurityConstants.GET_SOCIAL_USER_URL,
securityProperties.getBrowser().getSession().getSessionInvalidUrl()
)
.permitAll();

}
}

然后是 AuthorizeConfigManager, 代码如下:

1
2
3
4
5
6
7
8
public interface AuthorizeConfigManager {

/**
* 权限配置
* @param config
*/
void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config);
}

这里也提供一个实现类, DefaultAuthorizeConfigManager, 代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component
public class DefaultAuthorizeConfigManager implements AuthorizeConfigManager {

/**
* 收集系统中的所有的{@link AuthorizeConfigProvider}实现
*/
@Autowired
private Set<AuthorizeConfigProvider> authorizeConfigProviders;

@Override
public void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
for (AuthorizeConfigProvider authorizeConfigProvider : authorizeConfigProviders) {
authorizeConfigProvider.config(config);
}
// 除了上面配置的,其他的都需要登录后才能访问
config.anyRequest().authenticated();
}
}

最后在我们的安全配置中注入进去就可以了,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
@Override
protected void configure(HttpSecurity http) throws Exception {

// web网页登录的配置
applyPasswordAuthenticationConfig(http);

http
.apply(validateCodeSecurityConfig)
.and()
.apply(smsAuthenticationSecurityConfig)
.and()
.apply(securitySocialConfigurer)
.and()
.rememberMe()
.tokenRepository(persistentTokenRepository())
.tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())
.userDetailsService(userDetailsService)
.and()
.sessionManagement()
.invalidSessionStrategy(invalidSessionStrategy)
.maximumSessions(securityProperties.getBrowser().getSession().getMaximumSessions())
.maxSessionsPreventsLogin(securityProperties.getBrowser().getSession().isMaxSessionsPreventsLogin())
.expiredSessionStrategy(sessionInformationExpiredStrategy)
.and()
.and()
.logout()
.logoutUrl(securityProperties.getBrowser().getLogOutUrl())
.logoutSuccessHandler(logoutSuccessHandler)
.and()
.csrf().disable()
;
authorizeConfigManager.config(http.authorizeRequests());

}

最后一行代码就是把所有的配置都配置进去, app的配置也一样的

这时候调用方如果想增加自己的权限,只需要实现 AuthorizeConfigProvider 接口就行,如下:

1
2
3
4
5
6
7
8
9
10
11
@Component
public class MyAuthorizeConfigProvider implements AuthorizeConfigProvider {

@Override
public void config(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) {
config.antMatchers("/user/register")
.permitAll()
.antMatchers("/users")
.hasRole("ADMIN");
}
}

ok,到这儿权限配置分离就ok了

本文代码传送门