2017-12-06 143 views
8

Bir REST hizmeti geliştiriyorum. JSON kullanır ve bir sorun olduğunda önceden tanımlanmış bazı JSON nesnelerini iade etmelidir. Varsayılan Bahar yanıtı şöyle:Spring MVC (veya Spring Boot). Güvenlikle ilgili istisnalar için özel JSON yanıtı 401 Yetkilendirilmemiş veya 403 Yasak)

{ 
    "timestamp": 1512578593776, 
    "status": 403, 
    "error": "Forbidden", 
    "message": "Access Denied", 
    "path": "/swagger-ui.html" 
} 

I (a stacktrace ve ek istisna ilgili bilgilerle) kendine ait bir ile bu varsayılan JSON değiştirmek istiyor.

Yay, varsayılan davranışların üzerine yazmanın kullanışlı bir yolunu sunar. Özel bir özel durum işleyici ile bir @RestControllerAdvice fasulye tanımlamalıdır. Bu

@RestControllerAdvice 
public class GlobalExceptionHandler { 
    @ExceptionHandler(value = {Exception.class}) 
    public ResponseEntity<ExceptionResponse> unknownException(Exception ex) { 
    ExceptionResponse resp = new ExceptionResponse(ex, level); // my custom response object 
    return new ResponseEntity<ExceptionResponse>(resp, resp.getStatus()); 
    } 
    @ExceptionHandler(value = {AuthenticationException.class}) 
    public ResponseEntity<ExceptionResponse> authenticationException(AuthenticationExceptionex) { 
     // WON'T WORK 
    } 
} 

özel gibi ExceptionResponse nesne daha sonra özel bir mesaj dönüştürücü kullanılarak Bahar tarafından JSON dönüştürülecektir.

SORUN IS, InsufficientAuthenticationException gibi güvenlik istisnalar @ExceptionHandler olarak açıklamalı bir yöntemle ele alınamaz. Bu tür istisnalar, Spring MVC dağıtıcı sunucu uygulamasının girilmesinden önce gerçekleşir ve tüm MVC işleyicileri başlatıldı.

Özel bir süzgeç kullanarak bu özel durumu engellemek ve sıfırdan kendi JSON serileştirmesini oluşturmak mümkündür. Bu durumda, Spring MVC altyapısının geri kalanından tamamen bağımsız bir kod alacaktı. İyi değil.

Bulduğum çözüm işe yarıyor gibi görünüyor, ama delirmiş görünüyor.

@Configuration 
public class CustomSecurityConfiguration extends 
WebSecurityConfigurerAdapter { 

@Autowired 
protected RequestMappingHandlerAdapter requestMappingHandlerAdapter; 

@Autowired 
protected GlobalExceptionHandler exceptionHandler; 

@Override 
protected void configure(HttpSecurity http) throws Exception { 

    http.authorizeRequests() 
     .anyRequest() 
     .fullyAuthenticated(); 

    http.exceptionHandling() 
     .authenticationEntryPoint(authenticationEntryPoint()); 
} 

public AuthenticationEntryPoint authenticationEntryPoint() { 
    return new AuthenticationEntryPoint() { 
     @Override 
     public void commence(HttpServletRequest request, HttpServletResponse response, 
       AuthenticationException authException) throws IOException, ServletException { 

      try { 
       ResponseEntity<ExceptionResponse> objResponse = exceptionHandler.authenticationException(authException); 

       Method unknownException = exceptionHandler.getClass().getMethod("authenticationException", AuthenticationException.class); 

       HandlerMethod handlerMethod = new HandlerMethod(exceptionHandler, unknownException); 

       MethodParameter returnType = handlerMethod.getReturnValueType(objResponse); 

       ModelAndViewContainer mvc = new ModelAndViewContainer(); // not really used here. 

       List<HttpMessageConverter<?>> mconverters = requestMappingHandlerAdapter.getMessageConverters(); 

       DispatcherServletWebRequest webRequest = new DispatcherServletWebRequest(request, response); 

       HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(mconverters); 

       processor.handleReturnValue(objResponse, returnType, mvc, webRequest); 
      } catch (IOException e) { 
       throw e; 
      } catch (RuntimeException e) { 
       throw e;      
      } catch (Exception e) { 
       throw new ServletException(e); 
      } 
     } 
    }; 
} 

bu daha iyi görünüyor (, mesaj konvertörlerindeki MIME biçimi müzakere vb inşa Bahar ile birlikte) Bahar seri boru kullanmak için bir yolu var mı?

+0

Buradakine benzer, ancak orijinal istisnayı @ExceptionHandler tarafından "yakalanmasına" izin veren bir istisnayla sarmak gibi daha zarif bir çözüm: https://stackoverflow.com/questions/43632565/exceptionhandler-for- Ön kontrolör filtre yaylı güvenlik/43636386 – spekdrum

+0

http://www.baeldung.com/spring-security-custom-access-denied-page –

cevap

0

Yay aşağıdaki gibi özel bir işleyici şey uygulamak bir AccessDeniedException yani HTTP 403

durumunda bir özel JSON yanıtı elde etmek için aşağıdaki aşamaları izleyerek kullanılabilir AccessDeniedHandler ile işleme özel durum için dışı hazır destek sağlamak /deny dışlamak sağlamak -

public class CustomAccessDeniedHandler implements AccessDeniedHandler { 

    @Override 
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException exc) 
     throws IOException, ServletException { 
     System.out.println("Access denied .. "); 
     // do something 
     response.sendRedirect("/deny"); 
    } 
} 

Sonraki config bu işleyici fasulye oluşturmak ve güvenlik istisna işleyicisi (Önemli not bahar için tedarik kimlik doğrulaması başka isteği olan will) sonsuz /deny tekabül eden bir işleyici bilgileri denetçi sınıfındaki

@Bean 
public AccessDeniedHandler accessDeniedHandler(){ 
    return new CustomAccessDeniedHandler(); 
} 

@Override 
protected void configure(HttpSecurity http) throws Exception { 
    http.cors().and() 
      // some other configuration 
      .antMatchers("/deny").permitAll() 
      .and() 
      .exceptionHandling().accessDeniedHandler(accessDeniedHandler()); 
} 

sonraki hata) ayrılmasını tutmak ve sadece yeni SomeException örneği (ya da başka bir Exception olarak uygun atmak @RestControllerAdvice ilgili işleyicide durdurulmalıdır.

@GetMapping("/deny") 
public void accessDenied(){ 
    throw new SomeException("User is not authorized"); 
} 

Daha fazla bilgi gerekirse yorumlarda bildirin.

0

Bir sonraki yapılandırma çalışmalı, lütfen deneyin.

@Autowired 
private HandlerExceptionResolver handlerExceptionResolver; 

public AuthenticationEntryPoint authenticationEntryPoint() { 
    return new AuthenticationEntryPoint() { 
     @Override 
     public void commence(HttpServletRequest request, HttpServletResponse response, 
          AuthenticationException authException) throws IOException, ServletException { 

      try { 
       handlerExceptionResolver.resolveException(request, response, null, authException); 
      } catch (RuntimeException e) { 
       throw e; 
      } catch (Exception e) { 
       throw new ServletException(e); 
      } 
     } 
    }; 
} 
1

fasulye sınıf

@Component public class AuthenticationExceptionHandler implements AuthenticationEntryPoint, Serializable 

oluşturma ve commence() method geçersiz kılmak ve SecurityConfiguration sınıfta aşağıdaki örnekte

ObjectMapper mapper = new ObjectMapper(); 
String responseMsg = mapper.writeValueAsString(responseObject); 
response.getWriter().write(responseMsg); 

ve @Autowire AuthenticationExcetionHandler gibi nesne eşleyicisi 'ni kullanarak json tepkisi oluşturup configure(HttpSecurity http) method çizgiler

altında ekleyin
 http.exceptionHandling() 
      .authenticationEntryPoint(authenticationExceptionHandler) 

Bu yolla cikis json yanıtı 401/403'ü gönderebilmeniz gerekir. Yukarıdaki gibi aynı AccessDeniedHandler kullanabilirsiniz. Sorunun çözülmesine yardımcı olup olmadığını bize bildirin.