@ এক্সেকশনহ্যান্ডলার সহ স্প্রিং সুরক্ষা প্রমাণীকরণ ব্যতিক্রমগুলি পরিচালনা করুন


101

আমি স্প্রিং এমভিসি ব্যবহার করছি @ControllerAdviceএবং @ExceptionHandlerএকটি রেস্ট এপিআইয়ের সমস্ত ব্যতিক্রম হ্যান্ডেল করতে। ওয়েব এমভিসি নিয়ন্ত্রণকারীদের ফেলে দেওয়া ব্যতিক্রমগুলির জন্য এটি দুর্দান্ত কাজ করে তবে এটি বসন্ত সুরক্ষা কাস্টম ফিল্টারগুলির দ্বারা ছুঁড়ে দেওয়া ব্যতিক্রমগুলির জন্য কাজ করে না কারণ তারা নিয়ন্ত্রণকারী পদ্ধতিগুলি চাওয়ার আগে চালিত হয়।

আমার কাছে একটি কাস্টম বসন্ত সুরক্ষা ফিল্টার রয়েছে যা টোকেন ভিত্তিক লেখককে দেয়:

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

আমাকে যা করতে হবে তা হল বসন্ত সুরক্ষা প্রমাণীকরণের ধারণার জন্য এমনকি একটি বিশদ জেএসওএন বডি ফেরত। বসন্ত সুরক্ষা প্রমাণীকরণের এন্ট্রিপয়েন্ট এবং স্প্রিং এমভিসি @ এক্সপেশনহ্যান্ডলার একসাথে কাজ করার কোনও উপায় আছে কি?

আমি স্প্রিং সুরক্ষা 3.1.4 এবং স্প্রিং এমভিসি 3.2.4 ব্যবহার করছি।


9
আপনি পারবেন না ... (@)ExceptionHandlerঅনুরোধটি যদি হ্যান্ডল করে তবেই কেবলমাত্র কাজ করবে DispatcherServlet। তবে এই ব্যতিক্রমটি এর আগে ঘটে যেমন এটি দ্বারা নিক্ষেপ করা হয় Filter। সুতরাং আপনি কখনই এই ব্যতিক্রমটি হ্যান্ডেল করতে সক্ষম হবেন না (@)ExceptionHandler
এম। ডিনুম

ঠিক আছে, আপনি ঠিক বলেছেন। এন্ট্রিপয়েন্টের প্রতিক্রিয়া.সেন্ডআররের সাথে কোনও জসন বডি ফেরত দেওয়ার কোনও উপায় আছে কি?
নিকোলা

ব্যতিক্রমগুলি ধরার জন্য শৃঙ্খলে আপনাকে প্রথমে একটি কাস্টম ফিল্টার toোকানো এবং সেই অনুসারে ফিরে আসতে হবে বলে মনে হচ্ছে। ডকুমেন্টেশনগুলিতে ফিল্টারগুলি, তাদের উপাত্তগুলি
স্প্রিং-

4
যদি আপনার কেবল JSON এর প্রয়োজন হয় তবে কেবল এটির ভিতরে এটি তৈরি / লিখুন EntryPoint। আপনি সেখানে অবজেক্টটি তৈরি করতে MappingJackson2HttpMessageConverterএবং সেখানে একটি ইনজেকশন করতে চাইতে পারেন ।
এম। ডিনুম

@ এমডিনাম আমি এন্ট্রি পয়েন্টের ভিতরে জসন তৈরির চেষ্টা করব।
নিকোলা

উত্তর:


64

ঠিক আছে, আমি প্রমাণীকরণের এন্ট্রিপয়েন্ট থেকে নিজেই জসন লেখার পরামর্শ দিয়েছি এবং এটি কাজ করে।

কেবলমাত্র পরীক্ষার জন্য আমি প্রতিক্রিয়া.সেন্ডআরার সরিয়ে AutnticationEntryPoint পরিবর্তন করেছি

@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 অননুমোদিত এর সাথে আপনি কাস্টম জসন ডেটা প্রেরণ করতে পারেন।

স্পষ্টতই আপনি পরীক্ষার উদ্দেশ্যে যেমন জাসন তৈরি করেন নি তবে আপনি কিছু শ্রেণির উদাহরণকে সিরিয়ালাইজ করবেন।


4
জ্যাকসন ব্যবহারের উদাহরণ: অবজেক্টম্যাপার ম্যাপার = নতুন অবজেক্টম্যাপার (); mapper.writeValue (রেসপন্স.জেটআউটপুট স্ট্রিম (), নতুন ফেইলরেস্পোনস (401, authException.getLocalizedMessage (), "অ্যাক্সেস অস্বীকার", ""));
সাইরাস্মিথ

4
আমি জানি প্রশ্নটি কিছুটা পুরনো, তবে আপনি কি সুরক্ষাকনফাইগে আপনার প্রমাণীকরণের এন্ট্রিপয়েন্টটি নিবন্ধভুক্ত করেছেন?
21:51

4
@leventunver আপনি এখানে প্রবেশের পয়েন্টটি কীভাবে নিবন্ধভুক্ত করবেন তা পেতে পারেন: stackoverflow.com/questions/24684806/…
নিকোলা

37

এটি একটি খুব আকর্ষণীয় সমস্যা যে স্প্রিং সিকিউরিটি এবং স্প্রিং ওয়েব কাঠামো তারা যেভাবে প্রতিক্রিয়াটি পরিচালনা করছেন তাতে সামঞ্জস্যপূর্ণ নয়। আমি বিশ্বাস করি এটি কার্যকরভাবে MessageConverterএকটি ত্রুটি বার্তা হ্যান্ডলিং সমর্থন করে ।

আমি MessageConverterবসন্ত সুরক্ষায় ইনজেকশনের একটি দুর্দান্ত উপায় সন্ধান করার চেষ্টা করেছি যাতে তারা ব্যতিক্রমটি ধরতে পারে এবং বিষয়বস্তু আলোচনার ভিত্তিতে সঠিক ফর্ম্যাটে তাদের ফিরিয়ে দিতে পারে । তবুও, নীচের আমার সমাধানটি মার্জিত নয় তবে কমপক্ষে স্প্রিং কোডটি ব্যবহার করুন।

আমি ধরে নিলাম আপনি জ্যাকসন এবং জ্যাকএক্সবি লাইব্রেরিটি কীভাবে অন্তর্ভুক্ত করবেন তা জানেন, অন্যথায় এগিয়ে যাওয়ার কোনও মানে নেই। মোট 3 টি পদক্ষেপ আছে।

পদক্ষেপ 1 - ম্যাসেজকনভার্টারগুলি সঞ্চয় করে একটি স্বতন্ত্র শ্রেণি তৈরি করুন

এই শ্রেণি কোন যাদু খেলে না। এটি কেবল বার্তা রূপান্তরকারী এবং একটি প্রসেসরের সঞ্চয় করে 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 এবং আপনার জেএসওএন, এক্সএমএল বা কিছু অন্যান্য ফর্ম্যাটে ব্যতিক্রম পাওয়া উচিত।


4
আমি একটি ধরার চেষ্টা করছি InvalidGrantExceptionকিন্তু আপনার আমার সংস্করণটি CustomEntryPointচাওয়া হচ্ছে না। আমি কি অনুপস্থিত হতে পারে কোন ধারণা?
স্টেফান ফালক

@ ডিসপ্লে নাম সকল প্রমাণীকরণ ব্যতিক্রম যে হাতে ক্যাচ করা যাবে না AuthenticationEntryPoint এবং AccessDeniedHandlerযেমন UsernameNotFoundExceptionএবং InvalidGrantExceptionদ্বারা পরিচালিত করা যেতে পারে AuthenticationFailureHandlerযেমন এখানে ব্যাখ্যা
উইলসন

26

আমি খুঁজে পেয়েছি সবচেয়ে ভাল উপায় হ্যান্ডলারএক্সসেপশন রিসোলভারের ব্যতিক্রমটি অর্পণ করা

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

তারপরে আপনি পছন্দ হিসাবে প্রতিক্রিয়াটি ফর্ম্যাট করতে @ এক্সপশনহ্যান্ডলারটি ব্যবহার করতে পারেন।


10
একটি যাদুমন্ত্র মত কাজ করে. যদি স্প্রিং অটোওয়্যারিংয়ের জন্য 2 টি শিম সংজ্ঞা বলতে ত্রুটি ছুঁড়ে ফেলে তবে আপনাকে অবশ্যই বাছাইযোগ্য টিকা:
দাইভিধ

4
সচেতন হন যে নাল হ্যান্ডলারটি পাস করার পরে, @ControllerAdviceআপনি যদি টীকাতে বেসপ্যাকেজ নির্দিষ্ট করে থাকেন তবে আপনার কাজ করবে না। হ্যান্ডলারটি কল করার অনুমতি দেওয়ার জন্য আমাকে এটি পুরোপুরি সরিয়ে ফেলতে হয়েছিল।
জারমেক্স

দিলে কেন @Component("restAuthenticationEntryPoint")? কেন বিশ্রামপ্রযুক্তি এন্ট্রিপয়েন্টের মতো নামের প্রয়োজন? এটি কি কিছু স্প্রিং নামের সংঘর্ষ এড়ানোর জন্য?
থিম প্রোগ্রামার

@ জারমেক্স তাই নালার জায়গায়, আপনি কী পাস করেছেন? হ্যান্ডলার কিছুটা ঠিক তাই না? @ কন্ট্রোলার অ্যাডভাইস দ্বারা টীকাযুক্ত এমন একটি ক্লাসটি কি আমার পাস করা উচিত? ধন্যবাদ
থিম প্রোগ্রামার

@ থিপ্রোগ্রামার, এটির কাছাকাছি আসতে বেসপ্যাকেজ টীকা পরামিতি অপসারণ করতে আমাকে অ্যাপ্লিকেশনটিকে কিছুটা পুনর্গঠন করতে হয়েছিল - আদর্শ নয়!
জারমেক্স

5

স্প্রিং বুট এর ক্ষেত্রে এবং জাভা কনফিগারেশনের পরিবর্তে @EnableResourceServerপ্রসারিত ResourceServerConfigurerAdapterকরা এবং পদ্ধতির অভ্যন্তরে ওভাররাইড করে এবং WebSecurityConfigurerAdapterএকটি কাস্টম রেজিস্ট্রেশন করা তুলনামূলকভাবে সহজ এবং সুবিধাজনক ।AuthenticationEntryPointconfigure(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");
        }
    }

}

এখন, আপনি আপনার এমভিসি টিকা বা এক্সএমএল ভিত্তিক কনফিগারেশনে এর সিরিয়ালাইজারস, ডিসরিয়ালাইজারস এবং এর সাথে সংযুক্ত জ্যাকসন, জ্যাক্সবি বা আপনি যে কোনও প্রতিক্রিয়া সংস্থাগুলি রূপান্তর করতে ব্যবহার করতে পারেন।


আমি স্প্রিং বুটে খুব নতুন: অনুগ্রহ করে আমাকে বলুন "কীভাবে বার্তা কনভার্টর অবজেক্টটি প্রমাণীকরণের এন্ট্রি পয়েন্টে পাস করবেন"
কোনা সুরেশ

সেটারের মাধ্যমে। আপনি যখন এক্সএমএল ব্যবহার করেন তখন আপনাকে একটি <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শুধু জাভা pojo হয়, তাহলে আপনি তৈরি করতে পারেন পারেন আপনার নিজের
Vinit সোলাঙ্কি

2

আমি আমার ফিল্টারটিতে কেবল 'ব্যর্থ অ্যাটেনটিকেশন' পদ্ধতিটি ওভাররাইড করে তা হ্যান্ডেল করতে সক্ষম হয়েছি। সেখানে আমি পছন্দসই এইচটিটিপি স্থিতি কোড সহ ক্লায়েন্টকে একটি ত্রুটি প্রতিক্রিয়া প্রেরণ করছি।

@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

আপডেট: আপনি যদি কোডটি সরাসরি দেখতে পছন্দ করেন এবং পছন্দ করেন তবে আপনার জন্য আমার কাছে দুটি উদাহরণ রয়েছে, একটি হ'ল স্ট্যান্ডার্ড স্প্রিং সিকিউরিটি যা আপনি যা খুঁজছেন তা, অন্যটি রিঅ্যাকটিভ ওয়েব এবং প্রতিক্রিয়াশীল সুরক্ষার সমতুল্য ব্যবহার করছে:
- সাধারণ ওয়েব + জবটি সিকিউরিটি
- প্রতিক্রিয়াশীল জবটি

আমার জেএসওএন ভিত্তিক শেষ পয়েন্টগুলির জন্য আমি সর্বদা যেটি ব্যবহার করি তা নীচের মত দেখাচ্ছে:

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

আপনি আপনার ওয়েবসিকিউরিটি কনফিগুরির অ্যাডাপ্টার শ্রেণিতে সেট করেছেন ডিফল্ট প্রমাণীকরণের এন্ট্রিপয়েন্ট:

@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

আমি অবজেক্টম্যাপার ব্যবহার করছি। প্রতিটি রেস্ট সার্ভিস বেশিরভাগই জসনের সাথে কাজ করছে এবং আপনার কোনও একটি কনফিগারেশনে আপনি ইতিমধ্যে একটি অবজেক্ট ম্যাপারটি কনফিগার করেছেন।

কোডটি কোটলিনে লেখা আছে, আশা করি এটি ঠিক থাকবে।

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

টোকেনের মেয়াদ শেষ হওয়ার জন্য এবং অনুমোদনের শিরোনামটি হারিয়ে যাওয়ার জন্য প্রমাণীকরণের এন্ট্রিপয়েন্টের প্রয়োগ।


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
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.