Como desabilitar a segurança da mola para url particular

88

Estou usando o Spring Security sem monitoração de estado, mas, no caso de inscrição, quero desabilitar o Spring Security.

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

mas não está funcionando, estou recebendo o erro abaixo:

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

Acho que isso significa que os filtros de segurança de mola estão funcionando

O pedido do meu url sempre será "/ api / v1"

Minha configuração de primavera é

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

Meu filtro de autenticação é

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

Meu controlador é

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

Eu sou totalmente novo na primavera, por favor me ajude como fazê-lo?

Prabjot Singh
fonte
Dê uma olhada em: stackoverflow.com/questions/4487249/…
Krzysztof Cichocki

Respostas:

161

Ao usar permitAll significa todos os usuários autenticados, no entanto, você desabilitou o acesso anônimo, então isso não funcionará.

O que você deseja é ignorar certos URLs para substituir o configuremétodo que leva o WebSecurityobjeto e ignoreo padrão.

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

E remova essa linha da HttpSecuritypeça. Isso dirá ao Spring Security para ignorar esta URL e não aplicar nenhum filtro a ela.

M. Deinum
fonte
4
em qual arquivo isso foi escrito?
Jacob Zimmerman
3
@JacobZimmerman spring.io/blog/2013/07/03/… o configurador da aula de segurança web
Askar Ibragimov
1
Só gostaria de acrescentar que tem que estender WebSecurityConfigurerAdaptere overrideisso methodaí.
muasif80
20

Eu tenho um jeito melhor:

http
    .authorizeRequests()
    .antMatchers("/api/v1/signup/**").permitAll()
    .anyRequest().authenticated()
javajoker
fonte
3
Onde esse snippet deveria ser chamado?
Viacheslav Shalamov de
@ViacheslavShalamov Em seu WebSecurityConfig extends WebSecurityConfigurerAdapter's configure(HttpSecurity http)método. Consulte baeldung.com/java-config-spring-security
jAC 01 de
1
isso é mais comum na internet, na verdade é uma prática errada. se você permitir tudo, você quer dizer que ainda precisa ser autenticado, mas finalmente permitiu. então por que deveríamos fazer autenticação (quero dizer, os filtros de autenticação ainda serão acionados) para um acesso de inscrição?
Chao,
14
<http pattern="/resources/**" security="none"/>

Ou com configuração Java:

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

Em vez do antigo:

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

para exp. desative a segurança para uma página de login:

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

Esta pode não ser a resposta completa para sua pergunta, no entanto, se você está procurando uma maneira de desativar a proteção csrf, pode fazer:

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

}

Eu incluí a configuração completa, mas a linha principal é:

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

Como @ M.Deinum já escreveu a resposta.

Tentei com api /api/v1/signup. ele irá ignorar o filtro / filtro personalizado, mas uma solicitação adicional invocada pelo navegador para /favicon.ico, então, eu adiciono isso também em web.ignoring () e funciona para mim.

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

Talvez isso não seja necessário para a pergunta acima.

Eigenharsha
fonte
2

Se quiser ignorar vários endpoints de API, você pode usar o seguinte:

 @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
fonte
0

Eu enfrentei o mesmo problema aqui está a solução: ( 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
fonte