Spring Security 允许每个用户查看他们自己的个人资料,但不允许其他用户查看

Imp*_*Fox 7 java authorization spring-mvc spring-security

在带有 Spring Security 的 Spring MVC 中,是否可以实现这一点?

@Override WebSecurityConfigurerAdapter.configure(HttpSecurity)

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
            .authorizeRequests()
            .mvcMatchers("/users/{authentication.principal.username}").hasAnyRole(ADMIN, MANAGER)
            .antMatchers("/users/**").hasRole(ADMIN)
            .anyRequest().authorized()
    ...
}
Run Code Online (Sandbox Code Playgroud)

/users/**是一个限制区域,只能由管理员访问。但是管理员应该仍然能够看到他们自己的个人资料 ( /users/user_with_manager_role),并且只能看到他们自己的个人资料,而不是任何其他用户的个人资料(无论他们的角色如何)。


解决方案

我在安德鲁的回答中找到了解决方案。我的代码现在看起来像这样:

网络安全配置器适配器

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // added this annotation
public class SecurityConfig extends WebSecurityConfigurerAdapter
Run Code Online (Sandbox Code Playgroud)

@Override WebSecurityConfigurerAdapter.configure(HttpSecurity)

@Override
protected void configure(HttpSecurity http) throws Exception
{
    http
            .authorizeRequests()
            // removed /users handling
            .anyRequest().authorized()
    ...
}
Run Code Online (Sandbox Code Playgroud)

用户控制器

@Controller
@RequestMapping("/users")
public class UsersController
{
    @GetMapping("{username}")
    @PreAuthorize("authentication.principal.username == #username) || hasRole('ADMIN')")
    public String usersGet(@PathVariable("username") String username)
    {
        // do something with username, for example get a User object from a JPA repository
        return "user";
    }
}
Run Code Online (Sandbox Code Playgroud)

And*_*lko 3

恐怕这是不可能的:当设置此配置时,它没有关于{authentication.principal.username}将来某个时候将解决哪些问题的信息。

但是 Spring 为您提供了一堆内置方法安全表达式,您可以用它们来注释您的方法。

从像这样的简单表达式开始@PreAuthorize("hasRole('ADMIN')"),您最终可能会得到一个自定义表达式:

@XMapping(path = "/users/{username}")
@PreAuthorize("@yourSecurityService.isMyPage(authentication.principal, #username)")
public void yourControllerMethod(@PathVariable String username);
Run Code Online (Sandbox Code Playgroud)

@yourSecurityService.isMyPage(authentication.principal, #username)指的是你的@Service方法public boolean isMyPage(Principal, String)