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

时间:2014-09-30 19:43:08

标签: java spring spring-mvc authentication spring-security

我尝试在我的某个控制器上完成基于注释(使用@PreAuthorize)权限检查。我正在使用Java配置,并且SecurityConfig类扩展为WebSecurityConfigurerAdapter

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

但是 - 问题是,我没有希望SecurityConfig确定哪些方法需要使用antPattern()或类似的身份验证。这就是注释的用途!

如何配置我的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");
    }
}

我未受保护的方法失败了:

Full authentication is required to access this resource

我的受保护(但正确认证)测试失败了:

Error: Expected CSRF token not found. Has your session expired?

当我尝试这个时(尝试#2):

@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?

当我尝试这个时(尝试#3):

@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");
    }
}

我的身份验证方法正常运行。 (哇哇!)但是,我的未受保护的方法因401而失败,因为我的HttpSecurity似乎已配置为允许访问,如果您已经过身份验证 - 无论是否控制器方法用@PreAuthorize注释。

当我尝试这个时(尝试#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

<{> 我的身份验证测试方法失败且403使用MockMvc并使用标头发送请求:

{Content-Type=[application/json], Accept=[application/json], Authorization=[Basic Y3JhaWc6Y3JhaWdwYXNz]}

我已对其进行了解码和验证,以及使用方法/api/item的网址POST,该网址应定位相应的方法:

@RequestMapping(value = "/api/item", method = { RequestMethod.POST })
@PreAuthorize("hasRole('ROLE_USER')")
public void postNewItem(HttpServletRequest request, HttpServletResponse response) {
    ...
}

1 个答案:

答案 0 :(得分:0)

我做过类似的事情,唯一的区别是我有一些非常自定义的身份验证方法。如果你想要的只是检查用户角色,你应该在控制器方法上使用@Secured而不是@PreAuthorize,例如。

@Secured({"ROLE_SOMEROLE"})
public void doSomething(...) {
}

AuthenticationProvider中的角色设置为SimpleGrantedAuthorityUsernamePasswordAuthenticationToken的列表。 这是配置类:

@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/