目录
一、简介
我们希望微服务通过OAuth2+jwt的模式进行验证,但是有些资源我们并不想通过OAuth2+jwt进行验证,比如访问swagger和actuator端点,这些资源我们希望进行Basic验证。
二、知识点
-
@Order
spring security的验证是通过fliter链进行的,我们实现相应的ConfigurerAdapter就能自定义自己的fliter,我们通过@Order设置它在fliter链中的调用顺序。一般Basic验证应该先与其它验证
-
httpSecurity与authorizeRequests设置的区别
我们先看如下代码有什么不同
http.requestMatcher(EndpointRequest.toAnyEndpoint())
http.antMatcher(SWAGGER_URL)
http.authorizeRequests().requestMatcher(EndpointRequest.toAnyEndpoint())
http.authorizeRequests().antMatcher(SWAGGER_URL)
直接在http上定义,表明整个ConfigurerAdapter作用的资源。注意,这里requestMatcher和antMatcher只能传递一个参数。
在authorizeRequests上定义,表明实际需要控制权限的资源,往往其后需要跟authenticated和permitAll方法。
三、解决方案
有了以上知识点,解决方案也就很容易想出来了。Basic验证,OAuth2验证服务器,OAuth2资源服务器分别实现一个ConfigurerAdapter,通过在http上定义requestMatcher或antMatcher来进行区分资源。最后用@Order,把Basic验证的fliter设置在前面。
Basic验证
@Order(1)
@Configuration
@EnableWebSecurity
public class ServerWebSecurityConfig extends WebSecurityConfigurerAdapter {
private static final String SWAGGER_URL = "/swagger-ui.html";
private static final String REFRESH_URL = "/actuator/refresh";
@Override
protected void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new LuminaryRequestedMatcher())
.httpBasic()
.and()
.authorizeRequests()
// swagger页面需要添加登录校验
.antMatchers(SWAGGER_URL).authenticated()
// 监控节点需要添加登录校验
.requestMatchers(EndpointRequest.toAnyEndpoint()).authenticated()
.and()
// 允许刷新服务
.csrf().ignoringAntMatchers(REFRESH_URL);
}
private static class LuminaryRequestedMatcher implements RequestMatcher {
public boolean matches(HttpServletRequest request) {
AntPathRequestMatcher swaggerRequestMatcher = new AntPathRequestMatcher(SWAGGER_URL);
EndpointRequestMatcher endpointRequestMatcher = EndpointRequest.toAnyEndpoint();
return swaggerRequestMatcher.matches(request) || endpointRequestMatcher.matches(request);
}
}
}
Oauth2验证服务器
@Configuration
public class SsoWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Autowired
SmsCodeAuthenticationSecurityConfiguration smsCodeAuthenticationSecurityConfig;
@Autowired
ValidateCodeSecurityConfiguration validateCodeSecurityConfiguration;
@Autowired
protected AuthenticationSuccessHandler defaultAuthenticationSuccessHandler;
@Autowired
protected AuthenticationFailureHandler defaultAuthenticationFailureHandler;
@Bean(name = BeanIds.AUTHENTICATION_MANAGER)
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
@ConditionalOnMissingBean(PasswordEncoder.class)
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 非basic授权,表单方式
// 所有请求需要身份认证
http.formLogin()
.loginPage(Constants.LOGIN_CONTROLLER)
.loginProcessingUrl(Constants.DEFAULT_FORM_AUTHENTICATION_URL)
.successHandler(defaultAuthenticationSuccessHandler)
.failureHandler(defaultAuthenticationFailureHandler)
.and()
.apply(smsCodeAuthenticationSecurityConfig)
.and()
.apply(validateCodeSecurityConfiguration)
.and()
.authorizeRequests()
.antMatchers(
Constants.LOGIN_CONTROLLER,
Constants.IMAGE_CODE_CONTROLLER+"/**",
Constants.SMS_CODE_CONTROLLER+"/**",
"/swagger-resources/**",
"/v2/api-docs",
"/webjars/**",
"/oauth/check_token").permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}
}
OAuth2资源服务器
@Configuration
@EnableResourceServer
public class DefaultResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Autowired
SmsCodeAuthenticationSecurityConfiguration smsCodeAuthenticationSecurityConfiguration;
/**
*
* 安全验证配置
*
*/
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatcher(new OAuthRequestedMatcher())
.formLogin()
.loginPage(Constants.LOGIN_CONTROLLER)
// .loginProcessingUrl(Constants.DEFAULT_FORM_AUTHENTICATION_URL)
// .successHandler(defaultAuthenticationSuccessHandler)
// .failureHandler(defaultAuthenticationFailureHandler)
.and()
// .apply(smsCodeAuthenticationSecurityConfig)
// .and()
//.addFilterBefore(smsCodeFilter, UsernamePasswordAuthenticationFilter.class)
//.apply(validateCodeSecurityConfig)
//.and()
.authorizeRequests()
.antMatchers(
Constants.LOGIN_CONTROLLER,
Constants.IMAGE_CODE_CONTROLLER+"/**",
Constants.SMS_CODE_CONTROLLER+"/**",
"/oauth/check_token",
"/swagger-resources/**",
"/v2/api-docs",
"/webjars/**",
"/oauth/check_token"
// securityProperties.getBrowser().getLoginPage(),
// Constants.IMAGE_CODE_CONTROLLER,
// Constants.SMS_CODE_CONTROLLER
// securityProperties.getBrowser().getSession().getInvalidSessionUrl(),
// securityProperties.getBrowser().getLogoutUrl()
).permitAll()
.anyRequest()
.authenticated()
.and()
.csrf().disable();
}
private static class OAuthRequestedMatcher implements RequestMatcher {
public boolean matches(HttpServletRequest request) {
String auth = request.getHeader("Authorization");
boolean haveOauth2Token = (auth != null) && auth.startsWith("bearer");
boolean haveAccessToken = request.getParameter("access_token")!=null;
return haveOauth2Token || haveAccessToken;
}
}
}