本文就来介绍一下如何使用SwitchUserFilter进行帐户切换css
spring security内置的各类filter:spring
Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url@requires-channel |
SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | session-management/concurrency-control |
HEADERS_FILTER | HeaderWriterFilter | http/headers |
CSRF_FILTER | CsrfFilter | http/csrf |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509AuthenticationFilter | http/x509 |
PRE_AUTH_FILTER | AbstractPreAuthenticatedProcessingFilter Subclasses | N/A |
CAS_FILTER | CasAuthenticationFilter | N/A |
FORM_LOGIN_FILTER | UsernamePasswordAuthenticationFilter | http/form-login |
BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http/@servlet-api-provision |
JAAS_API_SUPPORT_FILTER | JaasApiIntegrationFilter | http/@jaas-api-provision |
REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousAuthenticationFilter | http/anonymous |
SESSION_MANAGEMENT_FILTER | SessionManagementFilter | session-management |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserFilter | N/A |
能够看到SwitchUserFilter是spring security提供的filter里头order顺序在最后的一个。前面讲到了FilterSecurityInterceptor主要用来进行鉴权处理,而SwitchUserFilter是用来作帐户切换的,把它放在FilterSecurityInterceptor以后,是要求对切换用户的功能进行鉴权,不然任何人均可以随意切换用户,那就安全故障了。api
@EnableWebSecurity @EnableGlobalMethodSecurity( securedEnabled = true, jsr250Enabled = true, prePostEnabled = true ) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public SwitchUserFilter switchUserFilter(UserDetailsService userDetailsService) throws Exception { SwitchUserFilter switchUserFilter = new SwitchUserFilter(); switchUserFilter.setUserDetailsService(userDetailsService); switchUserFilter.setTargetUrl("/session"); return switchUserFilter; } @Override protected void configure(HttpSecurity http) throws Exception { //Each <http> namespace block always creates an SecurityContextPersistenceFilter, an ExceptionTranslationFilter and a FilterSecurityInterceptor. These are fixed and cannot be replaced with alternatives. http .addFilterAfter(switchUserFilter(userDetailsService()),FilterSecurityInterceptor.class) .exceptionHandling().authenticationEntryPoint(new UnauthorizedEntryPoint()) .and() .csrf().disable() .authorizeRequests() .antMatchers("/login","/css/**", "/js/**","/fonts/**").permitAll() .antMatchers("/session").authenticated() .antMatchers("/login/impersonate").hasAuthority("ROLE_ADMIN") .antMatchers("/logout/impersonate").hasAuthority(SwitchUserFilter.ROLE_PREVIOUS_ADMINISTRATOR) .and() .formLogin() .permitAll() .and() .logout() .deleteCookies("JSESSIONID") .permitAll(); } @Bean @Override protected UserDetailsService userDetailsService(){ InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager(); manager.createUser(User.withUsername("demoUser1").password("123456") .authorities("ROLE_USER","read_x").build()); manager.createUser(User.withUsername("admin").password("123456") .authorities("ROLE_ADMIN").build()); return manager; } }
SwitchUserFilter默认的切换帐号的url为/login/impersonate,默认注销切换帐号的url为/logout/impersonate,默认的帐号参数为username
上面的配置为了方便验证,把切换完用户的targetUrl设置为/session,其代码以下安全
@RestController @RequestMapping("/session") public class SessionController { @GetMapping("") public Object getCurrentUser(){ return SecurityContextHolder.getContext().getAuthentication(); } }
首先用普通用户登陆,访问http://localhost:8080/login/impersonate?username=admin,发现返回403session
注销,使用管理员登陆,访问http://localhost:8080/login/impersonate?username=demoUser1,发现成功并跳转到sessionapp
{ "authorities": [ { "authority": "ROLE_USER" }, { "authority": "read_x" }, { "source": { "authorities": [ { "authority": "ROLE_ADMIN" } ], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": null }, "authenticated": true, "principal": { "password": null, "username": "admin", "authorities": [ { "authority": "ROLE_ADMIN" } ], "accountNonExpired": true, "accountNonLocked": true, "credentialsNonExpired": true, "enabled": true }, "credentials": null, "name": "admin" }, "authority": "ROLE_PREVIOUS_ADMINISTRATOR" } ], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": "1BF3D6F40A6F488EFD3ABE8F80E52872" }, "authenticated": true, "principal": { "password": "123456", "username": "demoUser1", "authorities": [ { "authority": "ROLE_USER" }, { "authority": "read_x" } ], "accountNonExpired": true, "accountNonLocked": true, "credentialsNonExpired": true, "enabled": true }, "credentials": "123456", "name": "demoUser1" }
能够发现有成功切换
以后再切换回来
http://localhost:8080/logout/impersonate?username=demoUser1ide
{ "authorities": [ { "authority": "ROLE_ADMIN" } ], "details": { "remoteAddress": "0:0:0:0:0:0:0:1", "sessionId": null }, "authenticated": true, "principal": { "password": null, "username": "admin", "authorities": [ { "authority": "ROLE_ADMIN" } ], "accountNonExpired": true, "accountNonLocked": true, "credentialsNonExpired": true, "enabled": true }, "credentials": null, "name": "admin" }
能够发现切换回来了,是否是很是神奇,太强大了,之后线上排查问题之类的,很是方便,爽歪歪了简直
若是你切换了不存在的用户,则报测试
This application has no explicit mapping for /error, so you are seeing this as a fallback. Sat Dec 16 14:36:28 CST 2017 There was an unexpected error (type=Unauthorized, status=401). Authentication Failed: demoUser2
SwitchUserFilter是个强大的filter,很是方便测试环境进行调试、测试,甚至能够用来进行上线问题排查。ui