@ExceptionHandler के साथ स्प्रिंग सुरक्षा प्रमाणीकरण अपवादों को संभालें


97

मैं स्प्रिंग एमवीसी का उपयोग कर रहा हूं @ControllerAdviceऔर @ExceptionHandlerबाकी एप्टी के सभी अपवादों को संभालने के लिए। यह वेब mvc नियंत्रकों द्वारा फेंके गए अपवादों के लिए ठीक काम करता है, लेकिन यह वसंत सुरक्षा कस्टम फ़िल्टर द्वारा फेंके गए अपवादों के लिए काम नहीं करता है क्योंकि वे नियंत्रक विधियों को लागू करने से पहले चलाते हैं।

मेरे पास एक कस्टम स्प्रिंग सिक्योरिटी फ़िल्टर है जो एक टोकन आधारित स्थिति करता है:

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

        }

    }

}

इस कस्टम प्रविष्टि बिंदु के साथ:

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

}

और विश्व स्तर पर अपवादों को संभालने के लिए इस वर्ग के साथ:

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

वसंत सुरक्षा प्रमाणीकरण के लिए भी मुझे एक विस्तृत JSON निकाय वापस करने की आवश्यकता है। वहाँ एक तरीका है वसंत सुरक्षा बनाने के लिए AuthenticationEntryPoint और स्प्रिंग mvc @ExceptionHandler एक साथ काम करते हैं?

मैं वसंत सुरक्षा 3.1.4 और वसंत mvc 3.2.4 का उपयोग कर रहा हूं।


9
आप नहीं कर सकते हैं ... (@)ExceptionHandlerकेवल तभी काम करेगा जब अनुरोध द्वारा नियंत्रित किया जाएगा DispatcherServlet। हालांकि यह अपवाद इससे पहले होता है क्योंकि इसे ए द्वारा फेंक दिया जाता है Filter। तो आप इस अपवाद को कभी नहीं संभाल पाएंगे (@)ExceptionHandler
एम। डाइनम

ठीक है, आप सही हैं। क्या प्रतिक्रिया के साथ-साथ जॉन्स बॉडी को वापस करने का कोई तरीका है।
निकोला

ऐसा लगता है कि आपको अपवाद को पकड़ने और तदनुसार लौटने के लिए श्रृंखला में पहले एक कस्टम फ़िल्टर सम्मिलित करने की आवश्यकता है। प्रलेखन फ़िल्टर, उनके उपनाम और उनके लागू होने के क्रम को सूचीबद्ध करता है: docs.spring.io/spring-security/site/docs/3.1.4.RELEASE/…
Romski

1
यदि एकमात्र स्थान आपको JSON की आवश्यकता है तो बस इसे अंदर लिखें / लिखें EntryPoint। आप वहां ऑब्जेक्ट का निर्माण करना चाहते हैं, और MappingJackson2HttpMessageConverterवहां एक इंजेक्शन लगा सकते हैं।
एम। डाइनम

@ M.Deinum मैं एंट्री पॉइंट के अंदर जोंस बनाने की कोशिश करूंगा।
निकोला

जवाबों:


58

ठीक है, मैंने कोशिश की कि खुद को ऑथेंटिकेशनएंट्रीप्रिएंट से जौन लिखने का सुझाव दिया जाए और यह काम करे।

बस परीक्षण के लिए मैंने response.sendError को हटाकर AutenticationEntryPoint को बदल दिया

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

    }
}

इस तरह से आप कस्टम अनसन डेटा को 401 अनधिकृत के साथ भेज सकते हैं, भले ही आप स्प्रिंग सिक्योरिटी ऑथेंटिकेशनएंट्रीपाइंट का उपयोग कर रहे हों।

जाहिर है कि आप जोंस का निर्माण नहीं करेंगे जैसा कि मैंने परीक्षण उद्देश्यों के लिए किया था लेकिन आप कुछ वर्ग उदाहरणों को क्रमबद्ध करेंगे।


3
जैक्सन का उपयोग करके उदाहरण: ObjectMapper mapper = new ObjectMapper (); mapper।
साइरसमिथ

1
मुझे पता है कि सवाल थोड़ा पुराना है, लेकिन क्या आपने SecurityConfig में अपना AuthenticationEntryPoint रजिस्टर किया है?
18

1
@leventunver यहाँ आप पा सकते हैं कि एंट्री पॉइंट कैसे रजिस्टर करें: stackoverflow.com/questions/24684806/…
निकोला

37

यह एक बहुत ही दिलचस्प समस्या है कि स्प्रिंग सिक्योरिटी और स्प्रिंग वेब फ्रेमवर्क उस तरह से सुसंगत नहीं है जिस तरह से वे प्रतिक्रिया को संभालते हैं। मेरा मानना ​​है कि इसे मूल रूप MessageConverterसे एक आसान तरीके से त्रुटि संदेश को संभालने का समर्थन करना है।

मैंने MessageConverterस्प्रिंग सिक्योरिटी में इंजेक्ट करने का एक सुंदर तरीका खोजने की कोशिश की ताकि वे अपवाद को पकड़ सकें और सामग्री बातचीत के अनुसार उन्हें एक सही प्रारूप में वापस कर सकें । फिर भी, नीचे मेरा समाधान सुरुचिपूर्ण नहीं है लेकिन कम से कम स्प्रिंग कोड का उपयोग करें।

मुझे लगता है कि आप जानते हैं कि जैक्सन और जेएक्सबी लाइब्रेरी को कैसे शामिल किया जाए, अन्यथा आगे बढ़ने का कोई मतलब नहीं है। कुल 3 चरण हैं।

चरण 1 - एक स्टैंडअलोन वर्ग बनाएं, MessageConverters संग्रहीत

इस वर्ग में कोई जादू नहीं है। यह बस संदेश कन्वर्टर्स और एक प्रोसेसर को संग्रहीत करता है RequestResponseBodyMethodProcessor। जादू उस प्रोसेसर के अंदर होता है जो सामग्री बातचीत सहित सभी काम करेगा और प्रतिक्रिया शरीर को तदनुसार परिवर्तित करेगा।

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

स्टेप 2 - ऑथेंटिकेशनएंट्रीप्राइवेट बनाएं

जैसा कि कई ट्यूटोरियल में, कस्टम त्रुटि हैंडलिंग को लागू करने के लिए यह वर्ग आवश्यक है।

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 - प्रवेश बिंदु पंजीकृत करें

जैसा कि उल्लेख किया गया है, मैं इसे जावा कॉन्फ़िगरेशन के साथ करता हूं। मैं यहां केवल प्रासंगिक कॉन्फ़िगरेशन दिखाता हूं, अन्य कॉन्फ़िगरेशन जैसे सत्र स्टेटलेस आदि होना चाहिए ।

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

कुछ प्रमाणीकरण विफल मामलों के साथ प्रयास करें, याद रखें अनुरोध हैडर में एक्सेप्ट शामिल होना चाहिए : XXX और आपको JSON, XML या कुछ अन्य प्रारूपों में अपवाद प्राप्त करना चाहिए।


1
मैं पकड़ने की कोशिश कर रहा हूं, InvalidGrantExceptionलेकिन मेरे आपके संस्करण को CustomEntryPointलागू नहीं किया जा रहा है। कोई भी विचार जो मुझे याद आ रहा है?
डिस्प्लेनेम

@प्रदर्शित होने वाला नाम। सभी प्रमाणीकरण अपवाद द्वारा पकड़ा नहीं किया जा सकता AuthenticationEntryPoint और AccessDeniedHandlerके रूप में इस तरह के UsernameNotFoundExceptionऔर InvalidGrantExceptionके द्वारा नियंत्रित किया जा सकता है AuthenticationFailureHandlerके रूप में यहां विस्तार से बताया
विल्सन

23

सबसे अच्छा तरीका मैंने पाया है कि हैंडलर एक्ससेप्शनResolver के अपवाद को सौंपना है

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

तो आप जिस तरह से प्रतिक्रिया चाहते हैं उसे प्रारूपित करने के लिए @ExceptionHandler का उपयोग कर सकते हैं।


9
एक जादू की तरह काम करता है। यदि स्प्रिंग ने यह कहते हुए एक त्रुटि फेंक दी कि ऑटोरिररिंग के लिए 2 बीन परिभाषा है, तो आपको क्वालीफायर एनोटेशन जोड़ना होगा: @Autowired @Qualifier ("हैंडलर एक्ससेप्शनResolver") निजी हैंडलरExceptionResolver रिसॉल्वर;
दाविद

1
ध्यान रखें कि एक अशक्त हैंडलर @ControllerAdviceको पास करने से, एनोटेशन पर आपके पास बेसपैकेज निर्दिष्ट करने पर आपका काम नहीं होगा। मुझे इसे पूरी तरह से हटा देना था ताकि हैंडलर को बुलाया जा सके।
जार्मेक्स

आपने क्यों दिया @Component("restAuthenticationEntryPoint")? RestAuthenticationEntryPoint जैसे नाम की आवश्यकता क्यों है? यह कुछ वसंत नाम टकराव से बचने के लिए है?
theprogrammer

@ जारमेक्स तो अशक्त के स्थान पर, आपने क्या किया? अपने हैंडलर के कुछ प्रकार सही है? क्या मुझे सिर्फ एक वर्ग पास करना चाहिए जिसे @ControllerAdvice के साथ एनोटेट किया गया है? धन्यवाद
theprogrammer

@theprogrammer, मुझे इसके आसपास पाने के लिए बेसपेकेज एनोटेशन पैरामीटर को हटाने के लिए एप्लिकेशन को थोड़ा पुनर्गठन करना पड़ा - आदर्श नहीं!
Jarmex

5

स्प्रिंग बूट के मामले में और @EnableResourceServer, जावा कॉन्फ़िगरेशन के ResourceServerConfigurerAdapterबजाय इसका विस्तार करना आसान और सुविधाजनक है और विधि के अंदर ओवरराइडिंग और उपयोग करके WebSecurityConfigurerAdapterएक कस्टम AuthenticationEntryPointको पंजीकृत करना है।configure(ResourceServerSecurityConfigurer resources)resources.authenticationEntryPoint(customAuthEntryPoint())

कुछ इस तरह:

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

एक अच्छा भी है OAuth2AuthenticationEntryPointजिसे बढ़ाया जा सकता है (क्योंकि यह अंतिम नहीं है) और एक कस्टम को लागू करते समय आंशिक रूप से फिर से उपयोग किया जाता है AuthenticationEntryPoint। विशेष रूप से, यह "डब्ल्यूडब्ल्यूडब्ल्यू-ऑथेंटिकेट" हेडर को त्रुटि-संबंधित विवरणों के साथ जोड़ता है।

आशा है कि यह किसी की मदद करेगा।


मैं यह कोशिश कर रहा हूं, लेकिन commence()मेरे कार्य को AuthenticationEntryPointआमंत्रित नहीं किया जा रहा है - क्या मुझे कुछ याद आ रहा है?
डिस्प्लेनेम

4

@ निकोला और @ विक्टर विंग से जवाब लेना और अधिक मानकीकृत तरीका जोड़ना:

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

}

अब, आप कॉन्फ़िगर किए गए जैक्सन, जैक्सब या जो भी आप अपने एमवीसी एनोटेशन या एक्सएमएल आधारित कॉन्फ़िगरेशन पर प्रतिक्रिया देने वाले निकायों को इसके धारावाहिकों, डीसेरिएलाइज़र और इसी तरह से परिवर्तित करने के लिए उपयोग कर सकते हैं।


मैं स्प्रिंग बूट के लिए बहुत नया हूं: कृपया मुझे बताएं कि "मैसेज को कैसे कनेक्ट करेंइंटरनेट ऑब्जेक्ट को ऑथेंटिकेशन प्वाइंट प्वाइंट"
कोना सुरेश

सेटर के माध्यम से। जब आप XML का उपयोग करते हैं तो आपको एक <property name="messageConverter" ref="myConverterBeanName"/>टैग बनाना होता है । जब आप एक @Configurationवर्ग का उपयोग करते हैं तो setMessageConverter()विधि का उपयोग करें ।
गेब्रियल विलेसीस

4

हमें HandlerExceptionResolverउस मामले में उपयोग करने की आवश्यकता है ।

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

इसके अलावा, आपको अपनी वस्तु वापस करने के लिए अपवाद हैंडलर वर्ग में जोड़ने की आवश्यकता है।

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

क्या आपको कई कार्यान्वयन के कारण प्रोजेक्ट चलाने के समय कोई त्रुटि मिल सकती है HandlerExceptionResolver, उस स्थिति में आपको जोड़ना @Qualifier("handlerExceptionResolver")होगाHandlerExceptionResolver


GenericResponseBeanसिर्फ जावा पूजो है, आप अपनी खुद की बना सकते हैं
विनित सोलंकी

2

मैं अपने फ़िल्टर में 'असफल असफलता' की विधि को ओवरराइड करके, इसे संभालने में सक्षम था। वहां, मैं क्लाइंट को वांछित HTTP स्थिति कोड के साथ एक त्रुटि प्रतिक्रिया भेजता हूं।

@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

अपडेट: यदि आप कोड को सीधे पसंद करते हैं और देखना पसंद करते हैं, तो मेरे पास आपके लिए दो उदाहरण हैं, एक मानक स्प्रिंग सिक्योरिटी का उपयोग करना, जो आप देख रहे हैं, दूसरा एक प्रतिक्रियाशील वेब और प्रतिक्रियाशील सुरक्षा के बराबर का उपयोग कर रहा है:
- सामान्य Web + Jwt Security
- Reactive Jwt

वह जो मैं हमेशा अपने JSON आधारित एंडपॉइंट्स के लिए उपयोग करता हूं वह निम्नलिखित है:

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

स्प्रिंग वेब स्टार्टर को जोड़ने के बाद ऑब्जेक्ट मैपर बीन बन जाता है, लेकिन मैं इसे कस्टमाइज़ करना पसंद करता हूं, इसलिए यहां ऑब्जेक्टमेपर के लिए मेरा कार्यान्वयन है:

  @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 वर्ग में सेट किया गया:

@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

फ़िल्टर को कस्टमाइज़ करें, और निर्धारित करें कि किस तरह की असामान्यता है, इससे बेहतर तरीका होना चाहिए

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

मैं ऑब्जेक्टमैपर का उपयोग कर रहा हूं। हर रेस्ट सर्विस ज्यादातर json के साथ काम कर रही है, और आपके किसी एक कॉन्फिगरेशन में आप पहले से ही किसी ऑब्जेक्ट मैपर को कॉन्फ़िगर कर चुके हैं।

कोड कोटलिन में लिखा गया है, उम्मीद है कि यह ठीक होगा।

@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

में ResourceServerConfigurerAdapterवर्ग, नीचे दिए गए कोड मेरे लिए काम किया कतरना। http.exceptionHandling().authenticationEntryPoint(new AuthFailureHandler()).and.csrf()..काम नहीं किया। इसलिए मैंने इसे अलग कॉल के रूप में लिखा।

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

टोकन समाप्ति और लापता प्राधिकरण हेडर को पकड़ने के लिए AuthenticationEntryPoint का कार्यान्वयन।


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

  }
}

काम नहीं कर रहा है .. फिर भी डिफ़ॉल्ट संदेश
aswzen
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.