วิธีปิดการใช้งาน Spring Security สำหรับ URL เฉพาะ


88

ฉันใช้ระบบรักษาความปลอดภัยสปริงแบบไม่ระบุสถานะ แต่ในกรณีของการสมัครใช้งานฉันต้องการปิดใช้งานการรักษาความปลอดภัยสปริงฉันปิดการใช้งานโดยใช้

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

ฉันเป็นมือใหม่สำหรับฤดูใบไม้ผลิโปรดช่วยฉันทำอย่างไร


คำตอบ:


161

เมื่อใช้งาน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/… the configurer for web security class
Askar Ibragimov

1
แค่อยากจะเพิ่มคุณต้องขยายWebSecurityConfigurerAdapterและoverrideสิ่งนี้methodในนั้น
muasif80

20

ฉันมีวิธีที่ดีกว่า:

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

3
ข้อมูลโค้ดนี้ควรเรียกว่าที่ไหน
Viacheslav Shalamov

@ViacheslavShalamov ในของคุณWebSecurityConfig extends WebSecurityConfigurerAdapter's configure(HttpSecurity http)วิธี ดูbaeldung.com/java-config-spring-security
jAC

1
สิ่งนี้พบบ่อยที่สุดในอินเทอร์เน็ตจริงๆแล้วเป็นการปฏิบัติที่ผิด หากคุณอนุญาตทั้งหมดคุณหมายความว่ายังต้องตรวจสอบสิทธิ์ แต่สุดท้ายคุณก็อนุญาต เหตุใดเราจึงควรทำการตรวจสอบสิทธิ์ (ฉันหมายถึงตัวกรองการตรวจสอบความถูกต้องจะยังคงถูกเรียกใช้) สำหรับการลงชื่อสมัครใช้
เจ้า

14
<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/v1/signupAPI มันจะข้ามตัวกรอง / ตัวกรองที่กำหนดเอง แต่มีการร้องขอเพิ่มเติมที่เรียกใช้โดยเบราว์เซอร์/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.**
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.