上面的表达式都是在WebSecurityConfig可以配置的: 每一个表达式都是对应了HttpSecurity的一个方法,并且是跟在antMatchers之后的。
比如:antMatchers("xxx").permitAll();
antMatchers---指定url
表达式---指定授权
如果需要多个表达式合并统一起来,需要自己通过.access来自己定义:
另一个需求是我们能不能通过.access自定义逻辑:让系统读取我们自己的逻辑而不是使用系统的默认逻辑。
目前我们的安全配置是写在我们的安全模块代码spring-security-core里面的,不管是spring-security-web和spring-security-app.都有一些针对url的安全配置。但是问题是这些url有些是我们的安全模块提供的 ,比如说一下url:
都是安全模块提供的。
但是用户注册("/user/register"),和获取用户的url("/user/*"),他其实是我们的spring-security-demo项目提供的。也就是使用我们安全模块的人提供的安全服务。对于安全模块来说,事先我们并不知道谁会使用我们的安全模块。我也不知道使用此安全模块的url服务。所以针对于使用安全模块的url服务我们应该剥离出去。
实现思路很简单,我们提供一个接口,在我们自己的权限模块里面去实现这个接口(把和安全模块相关的配置写到这个接口里面)。如果是用户模块的话,用户模块自己去实现此接口(将用户模块的url写到用户模块中) 如果我们应用A都需要多有的url服务,那么我们就让应用A去依赖这两个模块。应用A也有这个AuthorizeConfigProvider的实现。所以在应用A的spring容器中 一共有3个模块的权限配置提供者的实现:他们是权限模块、用户模块、应用A实现模块。
1.权限模块:权限模块自身的url权限配置
2.用户模块:用户模块的url权限配置
3.应用A实现模块:应用A特有的url权限配置
最后,在我们的权限模块core中只需要提供一个:AuthorizeConfigManager类,这个类的作用是:把Spring容器里面所有AuthorizeConfigProvider接口的实现全部收集起来。然后按照各个实现的配置给配置好。
假如我们现在有一个应用B,应用B也有自己的AuthorizeConfigProvider的实现并且依赖了权限模块实现、用户模块实现,此时AuthorizeConfigManager类也会收集起三个模块:权限模块、用户模块、应用A实现模块。最终应用A和应用B权限是不同的,但是我们的权限模块core是不管的。
我们将其封装到授权配置provider中去:
public interface AuthorizeConfigProvider { void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config); }
MyAuthorizeConfigProvider实现AuthorizeConfigProvider 接口,并申明为Spring的组件。
@Component public class MyAuthorizeConfigProvider implements AuthorizeConfigProvider { @Autowired private SecurityProperties securityProperties; @Override public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) { config.antMatchers(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL, SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_MOBILE, securityProperties.getBrowser().getLoginPage(), SecurityConstants.DEFAULT_VALIDATE_CODE_URL_PREFIX+"/*", securityProperties.getBrowser().getSignUpUrl()) .permitAll(); } }
public interface AuthorizeConfigManager { void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config); }
@Component public class MyAuthorizeConfigManager implements AuthorizeConfigManager { /** * 作用:把系统的provider全部收集起来 * @param config */ @Autowired private Set<AuthorizeConfigProvider> authorizeConfigProviders; @Override public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) { for (AuthorizeConfigProvider authorizeConfigProvider:authorizeConfigProviders){ authorizeConfigProvider.configure(config); } //除了上面配置的所有权限外,其他请求都需要授权 config.anyRequest().authenticated(); } }
@Configuration public class WebSecurityConfig extends AbstractChannelSecurityConfig { @Autowired private ValidateCodeSecurityConfig validateCodeSecurityConfig;//验证码过滤器配置 @Autowired private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig; //短信验证码授权配置 @Autowired private SpringSocialConfigurer mySocialSecurityConfig; @Autowired private UserDetailsService userDetailsService; @Autowired private SecurityProperties securityProperties; @Autowired private DataSource dataSource; @Autowired private AuthorizeConfigManager authorizeConfigManager; @Bean public PersistentTokenRepository persistentTokenRepository(){ JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl(); // //因为是Jdbc操作,所以我们需要注入数据源:org.springframework.jdbc.core.support.JdbcDaoSupport //tokenRepository继承org.springframework.jdbc.core.support.JdbcDaoSupport tokenRepository.setDataSource(dataSource); System.out.println("PersistentTokenRepository--dataSource:>dataSource"); //tokenRepository.setCreateTableOnStartup(true);//系统启动的时候创建:CREATE_TABLE_SQL表 return tokenRepository; } /** * 定义web安全配置类:覆盖config方法 * 1.参数为HttpSecurity */ @Override protected void configure(HttpSecurity http) throws Exception { applyPasswordAuthenticationConfig(http); http.apply(validateCodeSecurityConfig) .and() .apply(smsCodeAuthenticationSecurityConfig) .and() .apply(mySocialSecurityConfig)//配置第三方social .and() .rememberMe() .tokenRepository(persistentTokenRepository()) .tokenValiditySeconds(securityProperties.getBrowser().getRememberMeSeconds())//配置token失效秒数 .userDetailsService(userDetailsService) .and() .csrf().disable(); authorizeConfigManager.configure(http.authorizeRequests()); } }
@Configuration @EnableResourceServer public class MyResourceServerConfig extends ResourceServerConfigurerAdapter { @Autowired private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler; @Autowired private MyAuthenticationFailureHandler myAuthenticationFailureHandler; @Autowired private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig; //短信验证码授权配置 @Autowired private SpringSocialConfigurer mySocialSecurityConfig; @Autowired private SecurityProperties securityProperties; @Autowired private ValidateCodeSecurityConfig validateCodeSecurityConfig;//验证码过滤器配置 @Autowired private OpenIdAuthenticationSecurityConfig openIdAuthenticationSecurityConfig; @Autowired private AuthorizeConfigManager authorizeConfigManager; @Override public void configure(HttpSecurity http) throws Exception { http.formLogin() .loginPage(SecurityConstants.DEFAULT_UNAUTHENTICATION_URL) .loginProcessingUrl(SecurityConstants.DEFAULT_LOGIN_PROCESSING_URL_FORM) .successHandler(myAuthenticationSuccessHandler) .failureHandler(myAuthenticationFailureHandler); http.apply(validateCodeSecurityConfig) .and() .apply(smsCodeAuthenticationSecurityConfig) .and() .apply(mySocialSecurityConfig)//配置第三方social .and() .apply(openIdAuthenticationSecurityConfig) .and() .csrf().disable(); authorizeConfigManager.configure(http.authorizeRequests()); } }
除了core里面的配置,其他用户注册和用户获取的授权都是demo项目自己的配置。
首先先实现:AuthorizeConfigProvider的类:DemoAuthorizeConfigProvider
@Component public class DemoAuthorizeConfigProvider implements AuthorizeConfigProvider { @Override public void configure(ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry config) { config.antMatchers("/user").hasRole("ADMIN"); } }
然后在授权时候返回的用户配置上即可:
我们访问登录页面 http://127.0.0.1 :8088/login.html
访问: http://127.0.0.1 :8088/user时候: