Using Java config with Spring Security for annotation-based role checks and Basic HTTP Auth

假装没事ソ 提交于 2020-02-04 06:00:40

问题


I'm trying to accomplish annotation-based (using @PreAuthorize) permission checking on one of my controllers. I'm using Java config, and have a SecurityConfig class extending WebSecurityConfigurerAdapter.

I'm also using Basic HTTP Authentication to get to the methods that require authorization.

But - the problem is, I don't want the SecurityConfig determining which methods require authentication using an antPattern() or similar. That's what the annotations are for!

How can I configure my SecurityConfig class so that it properly uses HTTP Basic authentication and the configured AuthenticationManager for methods with @PreAuthorize, and allows anonymous access to controller methods that do not have any security annotations attached?

When I try this (Attempt #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");
    }
}

My unprotected methods fail with:

Full authentication is required to access this resource

And my protected (but properly-authenticating) tests fail with:

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

When I try this (Attempt #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");
    }
}

My unprotected methods fail with a 302 status code, and redirect to /login, and my protected/authenticating methods fail with:

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

When I try this (Attempt #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");
    }
}

My authenticating method works properly. (Woo hoo!) But, my unprotected method fails with 401 because my HttpSecurity has seemingly been configured to only allow access if you're authenticated - regardless of whether the controller method is annotated with @PreAuthorize.

When I try this (Attempt #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");
    }
}

My unprotected methods work properly (allow access), but my authenticating methods (whether they have the proper HTTP auth or not) fail with status code 403:

Error: Access Denied

My authenticating test method that fails with 403 uses MockMvc and sends in a request using headers:

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

Which I have decoded and verified, and a URL /api/item with method POST, which should target the corresponding method:

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

回答1:


I've done something similar the only difference is that i had some very customized authentication method. If the only thing you want is to check for user role you should use @Secured instead of @PreAuthorize on your controller methods e.g.

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

Where the role is set in AuthenticationProvider as a list of SimpleGrantedAuthority with UsernamePasswordAuthenticationToken. Here is the configuration class:

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

}

If your methods are annotated with @Secured and the current user does not have specified role the client will receive a 403 response else the request goes through. If you are trying to run unit testing you can use @Profile('test') on your beans and use AuthenticationProvider with hard coded data. Here a post on this type of approach: https://spring.io/blog/2011/02/14/spring-3-1-m1-introducing-profile/



来源:https://stackoverflow.com/questions/26128826/using-java-config-with-spring-security-for-annotation-based-role-checks-and-basi

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!