Як відключити захист від пружини для певної URL-адреси


85

Я використовую весняний захист без стану, але у випадку реєстрації я хочу відключити весняний захист

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

але це не працює, я отримую помилку нижче:

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

Я думаю, це означає, що працюють пружинні фільтри безпеки

Порядок моєї URL-адреси завжди буде "/ api / v1"

Моя весняна конфігурація

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

Мій фільтр автентифікації:

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

Мій контролер

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

Я абсолютно новачок у весні, допоможіть мені, як це зробити?


Відповіді:


156

Під permitAllйого використанням розуміється кожен аутентифікований користувач, однак ви вимкнули анонімний доступ, так що це не буде працювати.

Потрібно ігнорувати певні URL-адреси, оскільки це замінює configureметод, який бере WebSecurityоб’єкт і ignoreшаблон.

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

І видаліть цей рядок з HttpSecurityдеталі. Це дозволить Spring Security ігнорувати цю URL-адресу та не застосовувати до них жодних фільтрів.


4
в якому файлі це пишеться?
Jacob Zimmerman

3
@JacobZimmerman spring.io/blog/2013/07/03/… конфігуратор класу веб-безпеки
Аскар Ібрагімов

1
Просто хотів би додати, що ви повинні розширити WebSecurityConfigurerAdapterі overrideце methodв ньому.
muasif80

19

У мене є кращий спосіб:

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

3
Де цей фрагмент повинен називатися?
В’ячеслав Шаламов

@ViacheslavShalamov У вашій WebSecurityConfig extends WebSecurityConfigurerAdapter«S configure(HttpSecurity http)методом. Див. Baeldung.com/java-config-spring-security
jAC

1
це найпоширеніше в Інтернеті, насправді це неправильна практика. якщо ви дозволяєте все, ви маєте на увазі, що йому все ще потрібно автентифікуватися, але ви нарешті дозволите це. так навіщо нам робити аутентифікацію (я маю на увазі фільтри автентифікації все ще спрацьовуватимуть) для доступу до реєстрації?
Чао,

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

Або з конфігурацією Java:

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

Замість старого:

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

для досвіду вимкнути безпеку для сторінки входу:

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

9

Це може бути не повною відповіддю на ваше запитання, однак, якщо ви шукаєте спосіб відключити захист csrf, ви можете зробити:

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

}

Я включив повну конфігурацію, але ключовий рядок:

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

2

Як @ M.Deinum вже написав відповідь.

Я пробував з api /api/v1/signup. він буде обходити фільтр / спеціальний фільтр, але додатковий запит, викликаний браузером для /favicon.ico, отже, я додаю це також у web.ignoring (), і він працює для мене.

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

Можливо, це не потрібно для вищезазначеного питання.


2

Якщо ви хочете ігнорувати кілька кінцевих точок API, ви можете використовувати наступне:

 @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

Я зіткнувся з тією ж проблемою, ось рішення: ( Пояснено )

@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.**
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.