使用Java配置与Spring Security进行基于注释的角色检查和Basic HTTP身份验证。

3

我正在尝试使用基于注释的(使用@PreAuthorize)权限检查来完成我的控制器之一。 我正在使用Java配置,并且有一个扩展WebSecurityConfigurerAdapterSecurityConfig类。

我还在使用基本HTTP身份验证来访问需要授权的方法。

但是,问题是,我不想使用antPattern()或类似的方法让SecurityConfig确定哪些方法需要进行身份验证。这就是注释的作用所在!

我应该如何配置我的SecurityConfig类,以便它正确地使用HTTP基本身份验证和已配置的AuthenticationManager来处理带有@PreAuthorize的方法,并允许匿名访问没有任何安全注释的控制器方法?

当我尝试这样做(尝试#1):

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的未受保护的方法出现以下错误:

需要完整认证才能访问此资源

而我的受保护方法(但已正确认证)的测试出现以下错误:

错误:找不到预期的CSRF令牌。您的会话是否已过期?

当我尝试这样做(第二次尝试):

@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的未受保护的方法失败了,它返回一个状态码为302的重定向到/login。我的受保护/身份验证方法出现以下错误: Error: Expected CSRF token not found. Has your session expired? 当我尝试第三次时:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().anyRequest().authenticated().and().httpBasic();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的认证方法正常工作。(万岁!) 但是,我的未受保护的方法由于我的HttpSecurity看起来已经配置成只有在经过身份验证后才允许访问 - 无论控制器方法是否带有@PreAuthorize注释,因此失败并返回401错误。 当我尝试这样做时(第4次尝试):
@Configuration
@EnableWebSecurity
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable().authorizeRequests().anyRequest().permitAll();
    }

    @Autowired
    public void registerGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("craig").password("craigpass").roles("USER");
    }
}

我的未受保护的方法可以正常工作(允许访问),但我的身份验证方法(无论它们是否具有正确的HTTP身份验证)都会失败,并显示403状态码:
Error: Access Denied
我的身份验证测试方法使用MockMvc,并使用以下标头发送请求:
{Content-Type=[application/json], Accept=[application/json], Authorization=[Basic Y3JhaWc6Y3JhaWdwYXNz]}
我已对其进行解码和验证,并使用URL /api/item 和方法POST,应该定位到相应的方法:
@RequestMapping(value = "/api/item", method = { RequestMethod.POST })
@PreAuthorize("hasRole('ROLE_USER')")
public void postNewItem(HttpServletRequest request, HttpServletResponse response) {
    ...
}
1个回答

0
我做过类似的事情,唯一的区别是我有一些非常定制化的身份验证方法。如果你想要的只是检查用户角色,那么你应该在你的控制器方法上使用@Secured而不是@PreAuthorize,例如:
@Secured({"ROLE_SOMEROLE"})
public void doSomething(...) {
}

AuthenticationProvider 中,角色被设置为一个 SimpleGrantedAuthority 列表,并与 UsernamePasswordAuthenticationToken 一起使用。以下是配置类:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig  extends WebSecurityConfigurerAdapter {

@Autowired
private AuthenticationProvider authProvider;

@Autowired
private AuthenticationEntryPoint authenticationEntryPoint;

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

@Override
protected void configure(HttpSecurity http) throws Exception {
    // Had some other calls for CORS ajax requests.
    http.authorizeRequests()
            .antMatchers("/logout")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .httpBasic()
            .authenticationEntryPoint(authenticationEntryPoint)
            .csrf()
            .disable();
}

}

如果您的方法被注释为@Secured,并且当前用户没有指定的角色,则客户端将收到403响应,否则请求将继续进行。如果您正在尝试运行单元测试,可以在您的bean上使用@Profile('test'),并使用硬编码数据的AuthenticationProvider。这是一篇关于这种方法的文章: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接