1. 概述

在这个教程中,我们将通过一个简单的场景来演示如何在Spring Security中使用Run-As身份验证。

Run-As的高级解释是:用户可以作为具有不同权限的其他主体执行某些逻辑。

2. RunAsManager

首先,我们需要设置GlobalMethodSecurity并注入一个RunAsManager

这个管理器负责为临时的Authentication对象提供额外的权限:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected RunAsManager runAsManager() {
        RunAsManagerImpl runAsManager = new RunAsManagerImpl();
        runAsManager.setKey("MyRunAsKey");
        return runAsManager;
    }
}

通过重写runAsManager,我们替换基础类中的默认实现——它简单地返回null

还要注意key属性——框架使用它来保护和验证通过此管理器创建的临时Authentication对象。

最后,结果的Authentication对象是一个RunAsUserToken

3. 安全配置

为了验证我们的临时Authentication对象,我们将设置一个RunAsImplAuthenticationProvider

@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    ...
    auth.authenticationProvider(runAsAuthenticationProvider());
}

@Bean
public AuthenticationProvider runAsAuthenticationProvider() {
    RunAsImplAuthenticationProvider authProvider = new RunAsImplAuthenticationProvider();
    authProvider.setKey("MyRunAsKey");
    return authProvider;
}

当然,我们会使用与管理器相同的key,以便提供商可以检查RunAsUserToken身份验证对象是否使用相同的key创建。

4. 使用@Secured的控制器

现在,让我们看看如何使用Run-As身份验证替换:

@Controller
@RequestMapping("/runas")
class RunAsController {

    @Secured({ "ROLE_USER", "RUN_AS_REPORTER" })
    @RequestMapping
    @ResponseBody
    public String tryRunAs() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return "Current User Authorities inside this RunAS method only " + 
          auth.getAuthorities().toString();
    }

}

关键在于新的角色RUN_AS_REPORTER。这是Run-As功能的触发点,因为框架会因为前缀而以不同的方式处理它。

当请求通过此逻辑执行时,我们将有:

  • tryRunAs()方法调用之前,当前用户的权限是[ROLE_USER]
  • tryRunAs()方法内部,当前用户的权限是[ROLE_USER, ROLE_RUN_AS_REPORTER]
  • 临时的Authentication对象只在tryRunAS()方法调用期间替换现有的Authentication对象

5. 服务层实现

最后,让我们实现实际的逻辑——一个受保护的服务层:

@Service
public class RunAsService {

    @Secured({ "ROLE_RUN_AS_REPORTER" })
    public Authentication getCurrentUser() {
        Authentication authentication = 
          SecurityContextHolder.getContext().getAuthentication();
        return authentication;
    }
}

注意:

  • 要访问getCurrentUser()方法,需要ROLE_RUN_AS_REPORTER
  • 因此,我们只能在tryRunAs()控制器方法内部调用getCurrentUser()方法

6. 前端

接下来,我们将使用一个简单的前端来测试Run-As功能:

<html>
<body>
Current user authorities: 
    <span sec:authentication="principal.authorities">user</span>
<br/>
<span id="temp"></span>
<a href="#" onclick="tryRunAs()">Generate Report As Super User</a>
             
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"></script>
<script type="text/javascript">
function tryRunAs(){
    $.get( "/runas" , function( data ) {
         $("#temp").html(data);
    });
}
</script>
</body>
</html>

现在,当用户触发“以超级用户身份生成报告”操作时,他们将获得临时的ROLE_RUN_AS_REPORTER权限。

7. 总结

在这篇快速教程中,我们探讨了Spring Security中使用Run-As身份验证替换功能的一个简单示例。

本教程基于GitHub上可用的代码库