@ExceptionHandler ile bahar güvenliği kimlik doğrulama istisnalarını yönetin


101

Spring MVC'leri kullanıyorum @ControllerAdviceve @ExceptionHandlerREST Api'nin tüm istisnalarını işlemek için. Web mvc denetleyicileri tarafından atılan istisnalar için iyi çalışır, ancak denetleyici yöntemleri çağrılmadan önce çalıştıkları için bahar güvenliği özel filtreleri tarafından atılan istisnalar için çalışmaz.

Belirteç tabanlı kimlik doğrulaması yapan özel bir yay güvenlik filtrem var:

public class AegisAuthenticationFilter extends GenericFilterBean {

...

    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {

        try {

            ...         
        } catch(AuthenticationException authenticationException) {

            SecurityContextHolder.clearContext();
            authenticationEntryPoint.commence(request, response, authenticationException);

        }

    }

}

Bu özel giriş noktasıyla:

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
    }

}

Ve bu sınıfla küresel olarak istisnaları ele almak için:

@ControllerAdvice
public class RestEntityResponseExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler({ InvalidTokenException.class, AuthenticationException.class })
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    @ResponseBody
    public RestError handleAuthenticationException(Exception ex) {

        int errorCode = AegisErrorCode.GenericAuthenticationError;
        if(ex instanceof AegisException) {
            errorCode = ((AegisException)ex).getCode();
        }

        RestError re = new RestError(
            HttpStatus.UNAUTHORIZED,
            errorCode, 
            "...",
            ex.getMessage());

        return re;
    }
}

Yapmam gereken şey, bahar güvenliği AuthenticationException için bile ayrıntılı bir JSON gövdesi döndürmek. Yay güvenliği AuthenticationEntryPoint ve spring mvc @ExceptionHandler'ın birlikte çalışmasının bir yolu var mı?

Yay güvenliği 3.1.4 ve yay mvc 3.2.4 kullanıyorum.


9
Yapamazsınız ... (@)ExceptionHandlerYalnızca istek tarafından ele alınırsa çalışacaktır DispatcherServlet. Ancak bu istisna, bir Filter. Yani bu istisnayı asla bir (@)ExceptionHandler.
M.Deinum

Tamam sen haklısın. EntryPoint'teki response.sendError ile birlikte bir json gövdesini döndürmenin bir yolu var mı?
Nicola

İstisnayı yakalamak ve buna göre geri dönmek için zincirin başlarına özel bir filtre eklemeniz gerekiyor gibi görünüyor. Belgeler filtreleri, takma adlarını ve uygulandıkları sırayı listeler: docs.spring.io/spring-security/site/docs/3.1.4.RELEASE/…
Romski

1
JSON'a ihtiyacınız olan tek konumsa, onu EntryPoint. Nesneyi orada oluşturmak ve oraya bir enjekte etmek isteyebilirsiniz MappingJackson2HttpMessageConverter.
M.Deinum

@ M.Deinum Giriş noktasının içinde json oluşturmaya çalışacağım.
Nicola

Yanıtlar:


64

Tamam, json'u AuthenticationEntryPoint'ten kendim yazmayı önerdiği gibi denedim ve çalışıyor.

Sadece test etmek için response.sendError kaldırarak AutenticationEntryPoint'i değiştirdim

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint{

    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authenticationException) throws IOException, ServletException {

        response.setContentType("application/json");
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        response.getOutputStream().println("{ \"error\": \"" + authenticationException.getMessage() + "\" }");

    }
}

Bu şekilde, Spring Security AuthenticationEntryPoint kullanıyor olsanız bile 401 yetkisiz ile birlikte özel json verileri gönderebilirsiniz.

Açıkçası, benim test amacıyla yaptığım gibi json'u oluşturmazsınız, ancak bazı sınıf örneklerini serileştirirsiniz.


3
Jackson kullanan örnek: ObjectMapper mapper = new ObjectMapper (); mapper.writeValue (response.getOutputStream (), new FailResponse (401, authException.getLocalizedMessage (), "Erişim reddedildi", ""));
Cyrusmith

1
Sorunun biraz eski olduğunu biliyorum, ancak AuthenticationEntryPoint'inizi SecurityConfig'e kaydettiniz mi?
leventunver

1
@leventunver Burada giriş noktasını nasıl kaydedeceğinizi bulabilirsiniz: stackoverflow.com/questions/24684806/… .
Nicola

37

Bu, Spring Security ve Spring Web çerçevesinin yanıtı ele alma biçiminde pek tutarlı olmaması çok ilginç bir sorundur . Hata mesajı işlemeyi MessageConverterpratik bir şekilde desteklemesi gerektiğine inanıyorum .

MessageConverterSpring Security'ye enjekte etmenin zarif bir yolunu bulmaya çalıştım, böylece istisnayı yakalayabilirler ve içerik pazarlığına göre onları doğru bir formatta iade edebilirler . Yine de, aşağıdaki çözümüm zarif değil ama en azından Bahar kodunu kullanın.

Jackson ve JAXB kitaplığını nasıl dahil edeceğinizi bildiğinizi varsayıyorum, aksi takdirde devam etmenin bir anlamı yok. Toplamda 3 Adım vardır.

Adım 1 - MessageConverters'ı depolayan bağımsız bir sınıf oluşturun

Bu sınıf sihir yapmaz. Basitçe mesaj dönüştürücüleri ve bir işlemciyi depolar RequestResponseBodyMethodProcessor. Sihir, içerik pazarlığı ve yanıt gövdesini buna göre dönüştürme dahil tüm işi yapacak işlemcinin içindedir.

public class MessageProcessor { // Any name you like
    // List of HttpMessageConverter
    private List<HttpMessageConverter<?>> messageConverters;
    // under org.springframework.web.servlet.mvc.method.annotation
    private RequestResponseBodyMethodProcessor processor;

    /**
     * Below class name are copied from the framework.
     * (And yes, they are hard-coded, too)
     */
    private static final boolean jaxb2Present =
        ClassUtils.isPresent("javax.xml.bind.Binder", MessageProcessor.class.getClassLoader());

    private static final boolean jackson2Present =
        ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", MessageProcessor.class.getClassLoader()) &&
        ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", MessageProcessor.class.getClassLoader());

    private static final boolean gsonPresent =
        ClassUtils.isPresent("com.google.gson.Gson", MessageProcessor.class.getClassLoader());

    public MessageProcessor() {
        this.messageConverters = new ArrayList<HttpMessageConverter<?>>();

        this.messageConverters.add(new ByteArrayHttpMessageConverter());
        this.messageConverters.add(new StringHttpMessageConverter());
        this.messageConverters.add(new ResourceHttpMessageConverter());
        this.messageConverters.add(new SourceHttpMessageConverter<Source>());
        this.messageConverters.add(new AllEncompassingFormHttpMessageConverter());

        if (jaxb2Present) {
            this.messageConverters.add(new Jaxb2RootElementHttpMessageConverter());
        }
        if (jackson2Present) {
            this.messageConverters.add(new MappingJackson2HttpMessageConverter());
        }
        else if (gsonPresent) {
            this.messageConverters.add(new GsonHttpMessageConverter());
        }

        processor = new RequestResponseBodyMethodProcessor(this.messageConverters);
    }

    /**
     * This method will convert the response body to the desire format.
     */
    public void handle(Object returnValue, HttpServletRequest request,
        HttpServletResponse response) throws Exception {
        ServletWebRequest nativeRequest = new ServletWebRequest(request, response);
        processor.handleReturnValue(returnValue, null, new ModelAndViewContainer(), nativeRequest);
    }

    /**
     * @return list of message converters
     */
    public List<HttpMessageConverter<?>> getMessageConverters() {
        return messageConverters;
    }
}

Adım 2 - AuthenticationEntryPoint Oluşturun

Birçok öğreticide olduğu gibi, bu sınıf, özel hata işlemeyi uygulamak için gereklidir.

public class CustomEntryPoint implements AuthenticationEntryPoint {
    // The class from Step 1
    private MessageProcessor processor;

    public CustomEntryPoint() {
        // It is up to you to decide when to instantiate
        processor = new MessageProcessor();
    }

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

        // This object is just like the model class, 
        // the processor will convert it to appropriate format in response body
        CustomExceptionObject returnValue = new CustomExceptionObject();
        try {
            processor.handle(returnValue, request, response);
        } catch (Exception e) {
            throw new ServletException();
        }
    }
}

3. Adım - Giriş noktasını kaydedin

Belirtildiği gibi, bunu Java Config ile yapıyorum. Burada sadece ilgili yapılandırmayı gösteriyorum, oturum durumsuz vb. Gibi başka yapılandırma da olmalıdır .

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling().authenticationEntryPoint(new CustomEntryPoint());
    }
}

Bazı kimlik doğrulama başarısız durumlarını deneyin, istek başlığının Accept: XXX içermesi gerektiğini ve istisnayı JSON, XML veya diğer bazı biçimlerde almanız gerektiğini unutmayın.


1
Bir yakalamaya çalışıyorum InvalidGrantExceptionama senin versiyonun CustomEntryPointçağrılmıyor. Neyi özleyebileceğime dair bir fikrin var mı?
Stefan Falk

@ekran adı. Tarafından yakalanmış olamaz tüm kimlik doğrulama istisnalar AuthenticationEntryPoint ve AccessDeniedHandlergibi UsernameNotFoundExceptionve InvalidGrantExceptiontarafından ele alınabilir AuthenticationFailureHandlerolarak burada açıklanacaktır .
Wilson

26

Bulduğum en iyi yol, istisnayı HandlerExceptionResolver'a devretmek.

@Component("restAuthenticationEntryPoint")
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
        resolver.resolveException(request, response, null, exception);
    }
}

daha sonra yanıtı istediğiniz şekilde biçimlendirmek için @ExceptionHandler'ı kullanabilirsiniz.


10
Tıkır tıkır çalışıyor. Spring, otomatik yazım için 2 fasulye tanımı olduğunu söyleyen bir hata atarsa, niteleyici ek açıklaması eklemelisiniz: @Autowired @Qualifier ("handlerExceptionResolver") özel HandlerExceptionResolver çözücü;
Daividh

2
@ControllerAdviceEk açıklamada basePackages belirlediyseniz , boş bir işleyici ilettiğinizde çalışmayacağınızın farkında olun . İşleyicinin aranmasına izin vermek için bunu tamamen kaldırmak zorunda kaldım.
Jarmex

Neden verdin @Component("restAuthenticationEntryPoint")? Neden restAuthenticationEntryPoint gibi bir isme ihtiyaç var? Bazı Spring isim çarpışmalarını önlemek için mi?
theprogrammer

@Jarmex Peki null yerine neyi geçtin? onun bir tür işleyicisi değil mi? @ControllerAdvice ile açıklama eklenmiş bir sınıfı geçmeli miyim? Teşekkürler
theprogrammer

@theprogrammer, etrafından dolaşmak için basePackages açıklama parametresini kaldırmak için uygulamayı biraz yeniden yapılandırmam gerekti - ideal değil!
Jarmex

5

Spring Boot ve durumunda , Java yapılandırması yerine @EnableResourceServergenişletmek ve yöntemin içinde geçersiz kılarak ve kullanarak bir özel kaydetmek nispeten kolay ve kullanışlıdır .ResourceServerConfigurerAdapterWebSecurityConfigurerAdapterAuthenticationEntryPointconfigure(ResourceServerSecurityConfigurer resources)resources.authenticationEntryPoint(customAuthEntryPoint())

Bunun gibi bir şey:

@Configuration
@EnableResourceServer
public class CommonSecurityConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.authenticationEntryPoint(customAuthEntryPoint());
    }

    @Bean
    public AuthenticationEntryPoint customAuthEntryPoint(){
        return new AuthFailureHandler();
    }
}

Ayrıca OAuth2AuthenticationEntryPointgenişletilebilen (nihai olmadığı için) ve bir özel uygularken kısmen yeniden kullanılabilen bir güzel var AuthenticationEntryPoint. Özellikle, hatayla ilgili ayrıntıları içeren "WWW-Authenticate" başlıklarını ekler.

Umarım bu birine yardımcı olur.


Bunu çalışıyorum ama commence()benim işlevi AuthenticationEntryPointçağrılır almıyor - Bir şey mi kaçırıyorum?
Stefan Falk

4

@Nicola ve @Victor Wing'den yanıtlar almak ve daha standart bir yol eklemek:

import org.springframework.beans.factory.InitializingBean;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class UnauthorizedErrorAuthenticationEntryPoint implements AuthenticationEntryPoint, InitializingBean {

    private HttpMessageConverter messageConverter;

    @SuppressWarnings("unchecked")
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        MyGenericError error = new MyGenericError();
        error.setDescription(exception.getMessage());

        ServerHttpResponse outputMessage = new ServletServerHttpResponse(response);
        outputMessage.setStatusCode(HttpStatus.UNAUTHORIZED);

        messageConverter.write(error, null, outputMessage);
    }

    public void setMessageConverter(HttpMessageConverter messageConverter) {
        this.messageConverter = messageConverter;
    }

    @Override
    public void afterPropertiesSet() throws Exception {

        if (messageConverter == null) {
            throw new IllegalArgumentException("Property 'messageConverter' is required");
        }
    }

}

Artık yapılandırılmış Jackson, Jaxb veya MVC ek açıklamanızdaki yanıt gövdelerini dönüştürmek için kullandığınız her şeyi veya serileştiricileri, seriyi kaldırıcıları vb. İle XML tabanlı yapılandırmayı enjekte edebilirsiniz.


Spring boot konusunda çok yeniyim: lütfen bana "messageConverter nesnesini kimlik doğrulama giriş noktasına nasıl geçireceğimi" söyleyin
Kona Suresh

Pasör aracılığıyla. XML kullandığınızda bir <property name="messageConverter" ref="myConverterBeanName"/>etiket oluşturmanız gerekir . Bir @Configurationsınıfı kullandığınızda sadece setMessageConverter()yöntemi kullanın .
Gabriel Villacis

4

Bu HandlerExceptionResolverdurumda kullanmamız gerekiyor .

@Component
public class RESTAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    //@Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
        resolver.resolveException(request, response, null, authException);
    }
}

Ayrıca, nesnenizi döndürmek için istisna işleyici sınıfını eklemeniz gerekir.

@RestControllerAdvice
public class GlobalExceptionHandler extends ResponseEntityExceptionHandler {

    @ExceptionHandler(AuthenticationException.class)
    public GenericResponseBean handleAuthenticationException(AuthenticationException ex, HttpServletResponse response){
        GenericResponseBean genericResponseBean = GenericResponseBean.build(MessageKeys.UNAUTHORIZED);
        genericResponseBean.setError(true);
        response.setStatus(HttpStatus.UNAUTHORIZED.value());
        return genericResponseBean;
    }
}

birden fazla uygulaması nedeniyle bir proje çalıştırırken bir hata alabilir misiniz? HandlerExceptionResolverBu durumda @Qualifier("handlerExceptionResolver"),HandlerExceptionResolver


GenericResponseBeansadece java pojo, kendinizinkini yaratabilir misiniz
Vinit Solanki

2

Bunu, filtremdeki 'failfulAuthentication' yöntemini geçersiz kılarak halledebildim. Orada, istemciye istenen HTTP durum kodu ile bir hata yanıtı gönderiyorum.

@Override
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
        AuthenticationException failed) throws IOException, ServletException {

    if (failed.getCause() instanceof RecordNotFoundException) {
        response.sendError((HttpServletResponse.SC_NOT_FOUND), failed.getMessage());
    }
}

1

Güncelleme: Kodu doğrudan görmeyi seviyorsanız ve tercih ediyorsanız, sizin için iki örneğim var, aradığınız standart Spring Security, diğeri Reactive Web ve Reactive Security eşdeğerini kullanıyor:
- Normal Web + Jwt Güvenliği
- Reaktif Jwt

JSON tabanlı uç noktalarım için her zaman kullandığım jwt şuna benzer:

@Component
public class JwtAuthEntryPoint implements AuthenticationEntryPoint {

    @Autowired
    ObjectMapper mapper;

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthEntryPoint.class);

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException e)
            throws IOException, ServletException {
        // Called when the user tries to access an endpoint which requires to be authenticated
        // we just return unauthorizaed
        logger.error("Unauthorized error. Message - {}", e.getMessage());

        ServletServerHttpResponse res = new ServletServerHttpResponse(response);
        res.setStatusCode(HttpStatus.UNAUTHORIZED);
        res.getServletResponse().setHeader(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
        res.getBody().write(mapper.writeValueAsString(new ErrorResponse("You must authenticated")).getBytes());
    }
}

İlkbahar web başlatıcısını eklediğinizde nesne eşleştiricisi bir fasulye haline gelir, ancak onu özelleştirmeyi tercih ederim, işte benim ObjectMapper uygulamam:

  @Bean
    public Jackson2ObjectMapperBuilder objectMapperBuilder() {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder();
        builder.modules(new JavaTimeModule());

        // for example: Use created_at instead of createdAt
        builder.propertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE);

        // skip null fields
        builder.serializationInclusion(JsonInclude.Include.NON_NULL);
        builder.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        return builder;
    }

WebSecurityConfigurerAdapter sınıfınızda ayarladığınız varsayılan AuthenticationEntryPoint:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ............
   @Autowired
    private JwtAuthEntryPoint unauthorizedHandler;
@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable()
                .authorizeRequests()
                // .antMatchers("/api/auth**", "/api/login**", "**").permitAll()
                .anyRequest().permitAll()
                .and()
                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler)
                .and()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);


        http.headers().frameOptions().disable(); // otherwise H2 console is not available
        // There are many ways to ways of placing our Filter in a position in the chain
        // You can troubleshoot any error enabling debug(see below), it will print the chain of Filters
        http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
    }
// ..........
}

1

Filtreyi özelleştirin ve ne tür bir anormalliğin olduğunu belirleyin, bundan daha iyi bir yöntem olmalı

public class ExceptionFilter extends OncePerRequestFilter {

@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    String msg = "";
    try {
        filterChain.doFilter(request, response);
    } catch (Exception e) {
        if (e instanceof JwtException) {
            msg = e.getMessage();
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType(MediaType.APPLICATION_JSON.getType());
        response.getWriter().write(JSON.toJSONString(Resp.error(msg)));
        return;
    }
}

}


0

ObjectMapper'ı kullanıyorum. Her Dinlenme Hizmeti çoğunlukla json ile çalışıyor ve yapılandırmalarınızdan birinde bir nesne eşleştiricisi yapılandırdınız.

Kod Kotlin ile yazılmıştır, umarım iyi olur.

@Bean
fun objectMapper(): ObjectMapper {
    val objectMapper = ObjectMapper()
    objectMapper.registerModule(JodaModule())
    objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)

    return objectMapper
}

class UnauthorizedAuthenticationEntryPoint : BasicAuthenticationEntryPoint() {

    @Autowired
    lateinit var objectMapper: ObjectMapper

    @Throws(IOException::class, ServletException::class)
    override fun commence(request: HttpServletRequest, response: HttpServletResponse, authException: AuthenticationException) {
        response.addHeader("Content-Type", "application/json")
        response.status = HttpServletResponse.SC_UNAUTHORIZED

        val responseError = ResponseError(
            message = "${authException.message}",
        )

        objectMapper.writeValue(response.writer, responseError)
     }}

0

Gelen ResourceServerConfigurerAdaptersınıf, aşağıdaki kod benim için çalıştı parça alınmıştır. http.exceptionHandling().authenticationEntryPoint(new AuthFailureHandler()).and.csrf()..işe yaramadı. Bu yüzden ayrı arama olarak yazdım.

public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {

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

        http.exceptionHandling().authenticationEntryPoint(new AuthFailureHandler());

        http.csrf().disable()
                .anonymous().disable()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS).permitAll()
                .antMatchers("/subscribers/**").authenticated()
                .antMatchers("/requests/**").authenticated();
    }

Belirteçin sona erme tarihini ve eksik yetkilendirme başlığını yakalamak için AuthenticationEntryPoint'in uygulanması.


public class AuthFailureHandler implements AuthenticationEntryPoint {

  @Override
  public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e)
      throws IOException, ServletException {
    httpServletResponse.setContentType("application/json");
    httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

    if( e instanceof InsufficientAuthenticationException) {

      if( e.getCause() instanceof InvalidTokenException ){
        httpServletResponse.getOutputStream().println(
            "{ "
                + "\"message\": \"Token has expired\","
                + "\"type\": \"Unauthorized\","
                + "\"status\": 401"
                + "}");
      }
    }
    if( e instanceof AuthenticationCredentialsNotFoundException) {

      httpServletResponse.getOutputStream().println(
          "{ "
              + "\"message\": \"Missing Authorization Header\","
              + "\"type\": \"Unauthorized\","
              + "\"status\": 401"
              + "}");
    }

  }
}


çalışmıyor .. hala varsayılan mesajı göster
aswzen
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.