聊聊SwitchUserFilter的使用

本文就来介绍一下如何使用SwitchUserFilter进行账户切换

filter顺序

spring security内置的各种filter:

AliasFilter ClassNamespace Element or Attribute
CHANNEL_FILTERChannelProcessingFilterhttp/intercept-url@requires-channel
SECURITY_CONTEXT_FILTERSecurityContextPersistenceFilterhttp
CONCURRENT_SESSION_FILTERConcurrentSessionFiltersession-management/concurrency-control
HEADERS_FILTERHeaderWriterFilterhttp/headers
CSRF_FILTERCsrfFilterhttp/csrf
LOGOUT_FILTERLogoutFilterhttp/logout
X509_FILTERX509AuthenticationFilterhttp/x509
PRE_AUTH_FILTERAbstractPreAuthenticatedProcessingFilter SubclassesN/A
CAS_FILTERCasAuthenticationFilterN/A
FORM_LOGIN_FILTERUsernamePasswordAuthenticationFilterhttp/form-login
BASIC_AUTH_FILTERBasicAuthenticationFilterhttp/http-basic
SERVLET_API_SUPPORT_FILTERSecurityContextHolderAwareRequestFilterhttp/@servlet-api-provision
JAAS_API_SUPPORT_FILTERJaasApiIntegrationFilterhttp/@jaas-api-provision
REMEMBER_ME_FILTERRememberMeAuthenticationFilterhttp/remember-me
ANONYMOUS_FILTERAnonymousAuthenticationFilterhttp/anonymous
SESSION_MANAGEMENT_FILTERSessionManagementFiltersession-management
EXCEPTION_TRANSLATION_FILTERExceptionTranslationFilterhttp
FILTER_SECURITY_INTERCEPTORFilterSecurityInterceptorhttp
SWITCH_USER_FILTERSwitchUserFilterN/A

可以看到SwitchUserFilter是spring security提供的filter里头order顺序在最后的一个。

前面讲到了FilterSecurityInterceptor主要用来进行鉴权处理,而SwitchUserFilter是用来做账户切换的,把它放在FilterSecurityInterceptor之后,是要求对切换用户的功能进行鉴权,否则任何人都可以随意切换用户,那就安全故障了。

config

@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,发现返回403

注销,使用管理员登录,访问http://localhost:8080/login/impersonate?username=demoUser1,发现成功并跳转到session

{
  "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=demoUser1

{
  "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,非常方便测试环境进行调试、测试,甚至可以用来进行上线问题排查。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值