Come disabilitare la sicurezza primaverile per un determinato URL


88

Sto usando la sicurezza di primavera senza stato, ma in caso di registrazione desidero disabilitare la sicurezza di primavera. Ho disabilitato l'uso di

antMatchers("/api/v1/signup").permitAll().

ma non funziona, ricevo l'errore di seguito:

 message=An Authentication object was not found in the SecurityContext, type=org.springframework.security.authentication.AuthenticationCredentialsNotFoundException

Penso che questo significhi che i filtri di sicurezza primaverili funzionano

L'ordine del mio URL sarà sempre "/ api / v1"

La mia configurazione primaverile è

@Override
    protected void configure(HttpSecurity http) throws Exception {

         http.
         csrf().disable().
         sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
         and().
         authorizeRequests().
         antMatchers("/api/v1/signup").permitAll().
         anyRequest().authenticated().
         and().
         anonymous().disable();
        http.addFilterBefore(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
    }

Il mio filtro di autenticazione è

@Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = asHttp(request);
        HttpServletResponse httpResponse = asHttp(response);

        String username = httpRequest.getHeader("X-Auth-Username");
        String password = httpRequest.getHeader("X-Auth-Password");
        String token = httpRequest.getHeader("X-Auth-Token");

        String resourcePath = new UrlPathHelper().getPathWithinApplication(httpRequest);

        try {

            if (postToAuthenticate(httpRequest, resourcePath)) {            
                processUsernamePasswordAuthentication(httpResponse, username, password);
                return;
            }

            if(token != null){
                processTokenAuthentication(token);
            }
            chain.doFilter(request, response);
        } catch (InternalAuthenticationServiceException internalAuthenticationServiceException) {
            SecurityContextHolder.clearContext();
            logger.error("Internal authentication service exception", internalAuthenticationServiceException);
            httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        } catch (AuthenticationException authenticationException) {
            SecurityContextHolder.clearContext();
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
        } finally {
        }
    }

     private HttpServletRequest asHttp(ServletRequest request) {
            return (HttpServletRequest) request;
        }

        private HttpServletResponse asHttp(ServletResponse response) {
            return (HttpServletResponse) response;
        }

        private boolean postToAuthenticate(HttpServletRequest httpRequest, String resourcePath) {
            return Constant.AUTHENTICATE_URL.equalsIgnoreCase(resourcePath) && httpRequest.getMethod().equals("POST");
        }

        private void processUsernamePasswordAuthentication(HttpServletResponse httpResponse,String username, String password) throws IOException {
            Authentication resultOfAuthentication = tryToAuthenticateWithUsernameAndPassword(username, password);
            SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
            httpResponse.setStatus(HttpServletResponse.SC_OK);
            httpResponse.addHeader("Content-Type", "application/json");
            httpResponse.addHeader("X-Auth-Token", resultOfAuthentication.getDetails().toString());
        }

        private Authentication tryToAuthenticateWithUsernameAndPassword(String username,String password) {
            UsernamePasswordAuthenticationToken requestAuthentication = new UsernamePasswordAuthenticationToken(username, password);
            return tryToAuthenticate(requestAuthentication);
        }

        private void processTokenAuthentication(String token) {
            Authentication resultOfAuthentication = tryToAuthenticateWithToken(token);
            SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
        }

        private Authentication tryToAuthenticateWithToken(String token) {
            PreAuthenticatedAuthenticationToken requestAuthentication = new PreAuthenticatedAuthenticationToken(token, null);
            return tryToAuthenticate(requestAuthentication);
        }

        private Authentication tryToAuthenticate(Authentication requestAuthentication) {
            Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
            if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
                throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
            }
            logger.debug("User successfully authenticated");
            return responseAuthentication;
        }

Il mio controller è

@RestController
public class UserController {

    @Autowired
    UserService userService;

    /**
     * to pass user info to service
     */
    @RequestMapping(value = "api/v1/signup",method = RequestMethod.POST)
    public String saveUser(@RequestBody User user) {
        userService.saveUser(user);
        return "User registerted successfully";
    }
}

Sono totalmente nuovo alla primavera, per favore aiutami come farlo?


Risposte:


161

Quando lo usi permitAllsignifica che ogni utente autenticato, tuttavia hai disabilitato l'accesso anonimo in modo che non funzioni.

Quello che vuoi è ignorare determinati URL per questo sovrascrivere il configuremetodo che accetta WebSecurityobject e ignoreil pattern.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/api/v1/signup");
}

E rimuovi quella linea dalla HttpSecurityparte. Questo dirà a Spring Security di ignorare questo URL e di non applicare alcun filtro.


4
in quale file viene scritto?
Jacob Zimmerman

3
@JacobZimmerman spring.io/blog/2013/07/03/… il configuratore per il corso di sicurezza web
Askar Ibragimov

1
Vorrei solo aggiungere che devi estendere WebSecurityConfigurerAdaptere overridequesto methodin esso.
muasif80

20

Ho un modo migliore:

http
    .authorizeRequests()
    .antMatchers("/api/v1/signup/**").permitAll()
    .anyRequest().authenticated()

3
Dove dovrebbe essere chiamato questo snippet?
Viacheslav Shalamov

@ViacheslavShalamov Nella tua WebSecurityConfig extends WebSecurityConfigurerAdapter's configure(HttpSecurity http)metodo. Vedi baeldung.com/java-config-spring-security
jAC

1
questo è più comune in Internet, in realtà è una pratica sbagliata. se permetti tutto, significa che deve ancora autenticarsi ma alla fine lo permetti. quindi perché dovremmo fare l'autenticazione (voglio dire che i filtri di autenticazione saranno ancora attivati) per un accesso di registrazione?
Chao

14
<http pattern="/resources/**" security="none"/>

O con la configurazione Java:

web.ignoring().antMatchers("/resources/**");

Invece del vecchio:

 <intercept-url pattern="/resources/**" filters="none"/>

per exp. disabilitare la sicurezza per una pagina di accesso:

  <intercept-url pattern="/login*" filters="none" />

9

Questa potrebbe non essere la risposta completa alla tua domanda, tuttavia se stai cercando un modo per disabilitare la protezione CSRF puoi fare:

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/web/admin/**").hasAnyRole(ADMIN.toString(), GUEST.toString())
                .anyRequest().permitAll()
                .and()
                .formLogin().loginPage("/web/login").permitAll()
                .and()
                .csrf().ignoringAntMatchers("/contact-email")
                .and()
                .logout().logoutUrl("/web/logout").logoutSuccessUrl("/web/").permitAll();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("admin").password("admin").roles(ADMIN.toString())
                .and()
                .withUser("guest").password("guest").roles(GUEST.toString());
    }

}

Ho incluso la configurazione completa ma la linea chiave è:

.csrf().ignoringAntMatchers("/contact-email")

2

Poiché @ M.Deinum ha già scritto la risposta.

Ho provato con api /api/v1/signup. bypasserà il filtro / filtro personalizzato ma una richiesta aggiuntiva invocata dal browser per /favicon.ico, quindi, aggiungo questo anche in web.ignoring () e funziona per me.

@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring().antMatchers("/api/v1/signup", "/favicon.ico");
}

Forse questo non è richiesto per la domanda precedente.


2

Se desideri ignorare più endpoint API, puoi utilizzare come segue:

 @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests() 
            .antMatchers("/api/v1/**").authenticated()
            .antMatchers("api/v1/authenticate**").permitAll()
            .antMatchers("**").permitAll()
            .and().exceptionHandling().and().sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

0

Ho affrontato lo stesso problema, ecco la soluzione: ( spiegato )

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers(HttpMethod.POST,"/form").hasRole("ADMIN")  // Specific api method request based on role.
            .antMatchers("/home","/basic").permitAll()  // permited urls to guest users(without login).
            .anyRequest().authenticated()
            .and()
        .formLogin()       // not specified form page to use default login page of spring security.
            .permitAll()
             .and()
        .logout().deleteCookies("JSESSIONID")  // delete memory of browser after logout.

        .and()
        .rememberMe().key("uniqueAndSecret"); // remember me check box enabled.

    http.csrf().disable();  **// ADD THIS CODE TO DISABLE CSRF IN PROJECT.**
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.