मैंने अपने एपीआई के लिए प्रमाणीकरण लागू किया है और यह अपेक्षा के अनुरूप काम करता है। उपयोगकर्ता पहले उपयोगकर्ता नाम और पासवर्ड पास करके टोकन प्राप्त करने के लिए ऑथ एपीआई का उपयोग करता है। यह एपीआई एक टोकन देता है। उपयोगकर्ता तब टोकन पास करके सुरक्षित एपिस को कॉल करता है। यह समस्या तब होती है जब उपयोगकर्ता एक अमान्य टोकन पास करता है या टोकन पास नहीं करता है, डिफ़ॉल्ट त्रुटि ऑब्जेक्ट स्प्रिंग बूट से वापस आ जाता है। मैं इस ऑब्जेक्ट को कस्टमाइज़ करना चाहता हूं और इसके लिए, मैंने ResponseEntityExceptionHandler को विस्तारित करने वाला एक कस्टम अपवाद हैंडलर लिखा है लेकिन यह ट्रिगर नहीं हो रहा है क्योंकि नियंत्रक के आने से पहले अपवाद को फेंक दिया जाता है।

@ExceptionHandler(value = {InsufficientAuthenticationException.class})
public final ResponseEntity<Object> 
authenticationException(InsufficientAuthenticationException ex) {
    List<String> details = new ArrayList<>();
    details.add("Authentication is required to access this resource");
    ErrorResponse error = new ErrorResponse("error", "Unauthorized", details);
    return new ResponseEntity(error, HttpStatus.FORBIDDEN);
}

प्रमाणीकरण प्रदाता क्लाइंट द्वारा हेडर में भेजे गए प्रमाणीकरण टोकन के आधार पर उपयोगकर्ता को खोजने के लिए ज़िम्मेदार है। हमारा स्प्रिंग आधारित टोकन प्रमाणीकरण प्रदाता इस प्रकार दिखता है:

@Component
public class AuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
 @Autowired
 CustomerService customerService;

 @Override
 protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {
  //
 }

 @Override
 protected UserDetails retrieveUser(String userName, UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken) throws AuthenticationException {

  Object token = usernamePasswordAuthenticationToken.getCredentials();
  return Optional
   .ofNullable(token)
   .map(String::valueOf)
   .flatMap(customerService::findByToken)
   .orElseThrow(() -> new UsernameNotFoundException("Cannot find user with authentication token=" + token));
 }

टोकन प्रमाणीकरण फ़िल्टर हेडर से प्रमाणीकरण फ़िल्टर प्राप्त करने और प्रमाणीकरण के लिए प्रमाणीकरण प्रबंधक को कॉल करने के लिए ज़िम्मेदार है। प्रमाणीकरण फ़िल्टर इस तरह दिखता है:

public class AuthenticationFilter extends AbstractAuthenticationProcessingFilter {

    AuthenticationFilter(final RequestMatcher requiresAuth) {
        super(requiresAuth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException {

        Optional tokenParam = Optional.ofNullable(httpServletRequest.getHeader(AUTHORIZATION)); //Authorization: Bearer TOKEN
        String token= httpServletRequest.getHeader(AUTHORIZATION);
        token= StringUtils.removeStart(token, "Bearer").trim();
        Authentication requestAuthentication = new UsernamePasswordAuthenticationToken(token, token);
        return getAuthenticationManager().authenticate(requestAuthentication);

    }

    @Override
    protected void successfulAuthentication(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain, final Authentication authResult) throws IOException, ServletException {
        SecurityContextHolder.getContext().setAuthentication(authResult);
        chain.doFilter(request, response);
    }
}

स्प्रिंग सुरक्षा विन्यास इस तरह दिखता है:

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


 private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
  new AntPathRequestMatcher("/api/**")
 );

 AuthenticationProvider provider;

 public SecurityConfiguration(final AuthenticationProvider authenticationProvider) {
  super();
  this.provider = authenticationProvider;
 }

 @Override
 protected void configure(final AuthenticationManagerBuilder auth) {
  auth.authenticationProvider(provider);
 }

 @Override
 public void configure(final WebSecurity webSecurity) {
  webSecurity.ignoring().antMatchers("/token/**");
 }

 @Override
 public void configure(HttpSecurity http) throws Exception {
  http.sessionManagement()
   .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
   .and()
   .exceptionHandling()
   .and()
   .authenticationProvider(provider)
   .addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
   .authorizeRequests()
   .requestMatchers(PROTECTED_URLS)
   .authenticated()
   .and()
   .csrf().disable()
   .formLogin().disable()
   .httpBasic().disable()
   .logout().disable();

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

 @Bean
 AuthenticationFilter authenticationFilter() throws Exception {
  final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
  filter.setAuthenticationManager(authenticationManager());
  //filter.setAuthenticationSuccessHandler(successHandler());
  return filter;
 }

 @Bean
 AuthenticationEntryPoint forbiddenEntryPoint() {
  return new HttpStatusEntryPoint(HttpStatus.FORBIDDEN);
 }

    @Autowired
    private HandlerExceptionResolver handlerExceptionResolver;

    public AuthenticationEntryPoint authenticationEntryPoint() {
        log.error("in authenticationEntryPoint");
        return new AuthenticationEntryPoint() {
            @Override
            public void commence(HttpServletRequest request, HttpServletResponse response,
                                 AuthenticationException authException) throws IOException, ServletException {
                log.error("in commence");
                try {
                    log.error(authException.getLocalizedMessage());
                    handlerExceptionResolver.resolveException(request, response, null, authException);
                } catch (RuntimeException e) {
                    throw e;
                } catch (Exception e) {
                    throw new ServletException(e);
                }
            }
        };
    }
}

पुनश्च: देखें https://www .javadevjournal.com/spring/securing-a-restful-web-service-with-spring-security/

0
Tokyo 15 जून 2020, 13:18

1 उत्तर

सबसे बढ़िया उत्तर

चूंकि आप AbstractAuthenticationProcessingFilter को कस्टमाइज़ कर रहे हैं, आप इसके AuthenticationFailureHandler को भी कस्टमाइज़ कर सकते हैं, जिसे attemptAuthentication() फेंकने पर AuthenticationException लागू किया जाएगा। फिर आप वहां त्रुटि को संभाल सकते हैं।

एक उदाहरण है:

public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler{

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

          //create your custom error object
         CustomError error = xxxxx;


         response.setStatus(HttpStatus.FORBIDDEN.value());
         response.setContentType("application/json");
         response.setCharacterEncoding("UTF-8");

         // Format the custom error object as JSON string , for example using Jackson :
         ObjectMapper mapper = new ObjectMapper();
         response.getWriter().write(mapper.writeValueAsString(error));
    }

}

और इसका उपयोग करने के लिए कॉन्फ़िगर करें:

 @Bean
 AuthenticationFilter authenticationFilter() throws Exception {
   final AuthenticationFilter filter = new AuthenticationFilter(PROTECTED_URLS);
   filter.setAuthenticationFailureHandler(new MyAuthenticationFailureHandler());
   return filter;
 }
1
Ken Chan 16 जून 2020, 17:01