2015-06-04 20 views
7

Tôi gặp sự cố với hành vi mặc định trong bảo mật mùa xuân với ủy quyền các yêu cầu được cung cấp với Java Config.Bảo mật mùa xuân ẩn danh 401 thay vì 403

http 
     .... 
     .authorizeRequests() 
      .antMatchers("/api/test/secured/*").authenticated() 

Khi tôi thực hiện cuộc gọi đến ví dụ /api/test/secured/user mà không cần đăng nhập (với người dùng ẩn danh), nó trả về 403 Cấm. Có cách nào dễ dàng để thay đổi trạng thái thành 401 Không được ủy quyền khi người dùng ẩn danh muốn được bảo đảm bằng tài nguyên authenticated() hoặc @PreAuthorize?

Trả lời

5

tôi đã có giải pháp here: mã nguồn

http 
    .authenticationEntryPoint(authenticationEntryPoint) 

AuthenticationEntryPoint:

@Component 
public class Http401UnauthorizedEntryPoint implements AuthenticationEntryPoint { 

    private final Logger log = LoggerFactory.getLogger(Http401UnauthorizedEntryPoint.class); 

    /** 
    * Always returns a 401 error code to the client. 
    */ 
    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException arg2) throws IOException, 
      ServletException { 

     log.debug("Pre-authenticated entry point called. Rejecting access"); 
     response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access Denied"); 
    } 
} 
+0

này hoạt động! Cảm ơn bạn. – Mati

+0

Xe tăng, giải pháp này cũng làm việc cho vấn đề của tôi! Tôi muốn làm ngược lại: thay đổi 401 thành 403. xác thực đường nốiEntryPoint đã chuyển sang httpBasic(), tôi đã yêu cầu chỉnh sửa cho điều này. – switch87

13

Với 4.x an ninh mùa xuân đã có một lớp cho rằng

org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint 

mùa xuân boot cũng bao gồm một

org.springframework.boot.autoconfigure.security.Http401AuthenticationEntryPoint 

và cả những lợi ích mà họ yêu cầu các nhà phát triển để sử dụng spec compliant như 401 responses requires that header WWW-Authenticate phải được thiết lập, ví dụ 401 trả lời có thể là:

HTTP/1.1 401 Unauthorized 
WWW-Authenticate: Bearer realm="example", 
        error="invalid_token", 
        error_description="The access token expired" 

Vì vậy, trong cấu hình bảo mật của bạn, bạn xác định và autowire một đậu của lớp

vì vậy, ví dụ với ứng dụng khởi động mùa xuân:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity(prePostEnabled=true) 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{ 

    @Bean 
    public Http401AuthenticationEntryPoint securityException401EntryPoint(){ 

     return new Http401AuthenticationEntryPoint("Bearer realm=\"webrealm\""); 
    } 

    @Autowired 
    private Http401AuthenticationEntryPoint authEntrypoint; 
... 
@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http 
      .authorizeRequests() 
       .antMatchers("/login").anonymous() 
       .antMatchers("/").anonymous() 
       .antMatchers("/api/**").authenticated() 
      .and() 
      .csrf() 
       .disable() 
       .headers() 
       .frameOptions().disable() 
      .and() 
       .sessionManagement() 
       .sessionCreationPolicy(SessionCreationPolicy.STATELESS) 
      .and() 
      .logout() 
       .permitAll() 
     .exceptionHandling().authenticationEntryPoint(authEntrypoint); 
} 

dòng tương ứng là:

.exceptionHandling().authenticationEntryPoint(authEntrypoint); 
+1

Thay vì tiêm bean bạn vừa tạo, bạn có thể gọi hàm trực tiếp: '.exceptionHandling(). AuthenticationEntryPoint (securityException401EntryPoint());'. Nó sẽ nhận được cùng một ví dụ bởi vì các cuộc gọi đến các chức năng chú thích '@ Bean' được proxyfied. – EliuX

+1

Lớp đó [đã bị xóa] (https://github.com/spring-projects/spring-boot/issues/10715) trong Spring Boot 2. Tôi vừa tạo lại nó trong ứng dụng của mình từ Spring Boot 1.5.10 kiểm soát nguồn [ here] (https://github.com/spring-projects/spring-boot/blob/v1.5.10.RELEASE/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/security/Http401AuthenticationEntryPoint .java) – CorayThan

0

Bạn cần mở rộng AuthenticationEntryPoint để tùy chỉnh dựa trên ngoại lệ.

@ControllerAdvice 
public class MyAuthenticationEntryPoint implements AuthenticationEntryPoint { 
    @Override 
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) 
     throws IOException, ServletException { 
    // 401 
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authentication Failed"); 
    } 

    @ExceptionHandler (value = {AccessDeniedException.class}) 
    public void commence(HttpServletRequest request, HttpServletResponse response, 
     AccessDeniedException accessDeniedException) throws IOException { 
    // 401 
    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization Failed : " + accessDeniedException.getMessage()); 
    } 
} 

Xác định AuthenticationEntryPoint tùy chỉnh trên trong SecurityConfig của bạn như dưới đây:

@Configuration 
@EnableWebSecurity 
@EnableGlobalMethodSecurity (prePostEnabled = true) 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
    http.exceptionHandling() 
     .authenticationEntryPoint(new MyAuthenticationEntryPoint()); 
    } 
} 
Các vấn đề liên quan