Cómo deshabilitar la seguridad de primavera para una URL particular

85

Estoy usando seguridad de primavera sin estado, pero en caso de registro quiero deshabilitar la seguridad de primavera.

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

pero no funciona, recibo el siguiente error:

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

Creo que esto significa que los filtros de seguridad de primavera están funcionando.

El orden de mi URL siempre será "/ api / v1"

Mi configuración de primavera es

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

Mi filtro de autenticación es

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

Mi controlador es

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

Soy totalmente nuevo en la primavera, por favor ayúdame a hacerlo.

Prabjot Singh
fuente
Eche un vistazo a: stackoverflow.com/questions/4487249/…
Krzysztof Cichocki

Respuestas:

156

Cuando se usa permitAll, significa cada usuario autenticado, sin embargo, deshabilitó el acceso anónimo para que no funcione.

Lo que desea es ignorar ciertas URL para que esto anule el configuremétodo que toma el WebSecurityobjeto y ignoreel patrón.

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

Y quita esa línea de la HttpSecuritypieza. Esto le dirá a Spring Security que ignore esta URL y no les aplique ningún filtro.

M. Deinum
fuente
4
¿En qué archivo se escribe esto?
Jacob Zimmerman
3
@JacobZimmerman spring.io/blog/2013/07/03/… el configurador para la clase de seguridad web
Askar Ibragimov
1
Solo me gustaría agregar que tienes que extender WebSecurityConfigurerAdaptery overrideesto methoden él.
muasif80
19

Tengo una mejor manera:

http
    .authorizeRequests()
    .antMatchers("/api/v1/signup/**").permitAll()
    .anyRequest().authenticated()
javajoker
fuente
3
¿Dónde se supone que debe llamarse este fragmento?
Viacheslav Shalamov
En su @ViacheslavShalamov WebSecurityConfig extends WebSecurityConfigurerAdapter's configure(HttpSecurity http)método. Ver baeldung.com/java-config-spring-security
jAC
1
esto es más común en Internet, en realidad es una práctica incorrecta. si lo permite todo, quiere decir que aún necesita autenticarse pero finalmente lo permite. Entonces, ¿por qué deberíamos hacer la autenticación (me refiero a que los filtros de autenticación aún se activarán) para un acceso de registro?
Chao
13
<http pattern="/resources/**" security="none"/>

O con la configuración de Java:

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

En lugar de lo viejo:

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

por exp. deshabilitar la seguridad para una página de inicio de sesión:

  <intercept-url pattern="/login*" filters="none" />
Sagar Bhandari
fuente
9

Es posible que esta no sea la respuesta completa a su pregunta, sin embargo, si está buscando una forma de desactivar la protección csrf, puede hacerlo:

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

}

He incluido la configuración completa, pero la línea clave es:

.csrf().ignoringAntMatchers("/contact-email")
Tomasz Mularczyk
fuente
2

Como @ M.Deinum ya escribió la respuesta.

Intenté con api /api/v1/signup. omitirá el filtro / filtro personalizado, pero una solicitud adicional invocada por el navegador /favicon.ico, por lo tanto, agrego esto también en web.ignoring () y funciona para mí.

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

Quizás esto no sea necesario para la pregunta anterior.

eigenharsha
fuente
2

Si desea ignorar varios puntos finales de API, puede usar lo siguiente:

 @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);
    }
vishwaraj
fuente
0

Me enfrenté al mismo problema, aquí está la solución: ( Explicado )

@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.**
}
shubham1js
fuente