Spring Security如何处理UsernameNotFoundException [英] How to handle UsernameNotFoundException spring security

查看:1004
本文介绍了Spring Security如何处理UsernameNotFoundException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何处理 UsernameNotFoundException 吗?

在春季安全性中,找不到用户名 UserDetailsS​​ervice 实现会引发 UsernameNotFoundException 。像这样的例子:

In spring security when username not found the UserDetailsService implementation throws a UsernameNotFoundException. For example like this:

   @Override
   @Transactional
   public UserDetails loadUserByUsername(java.lang.String username) throws UsernameNotFoundException {
       logger.info("Load user by username: {}", username);
       User user = userRepository.findUserByUsername(username).orElseThrow(
                   () -> new UsernameNotFoundException("User Not Found with -> username or email: " + username));

       return UserPrinciple.build(user);
   }

我想构建一个自定义的找不到用户REST响应。
如何捕获/处理此异常?我已经在WebSecurityConfigurerAdapter实现的处理程序中实现了处理程序方法:

I would like to build a custom "User not found REST response". How should I catch/handle this exception? I have implemented a handler method in the WebSecurityConfigurerAdapter implementation the handler:

  private static void handleException(HttpServletRequest req, HttpServletResponse rsp, AuthenticationException e)
           throws IOException {
       PrintWriter writer = rsp.getWriter();
       writer.println(new ObjectMapper().writeValueAsString(new AuthResponse("", null, null, null, null,
               "Authentication failed.", false)));
       rsp.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
   }

但是此方法应等待 AuthenticationException 异常,在运行时,异常类型为 java.lang.NullPointerException ,因此我无法投射或检索初始的 UsernameNotFoundException

But this method should wait for an AuthenticationException exception which, and during runtime the type of the exception is java.lang.NullPointerException so I'm not able to cast or retrieve the the initial UsernameNotFoundException.

任何建议将不胜感激。
很多方面的问候:)。

Any advice would be appreciated. Many many regards :).

推荐答案

安全层先于控制器和 @ControllerAdvice
因此, @ControllerAdvice 是不可选项,因为 UsernameNotFoundException AuthenticationException ,从而使 @ControllerAdvice 中的异常处理程序无法访问。

Security layer comes before anything in the controllers and @ControllerAdvice. Hence @ControllerAdvice isn't an option since UsernameNotFoundException which is a subclass of AuthenticationException is thrown during authenticaton, making your exception handlers in @ControllerAdvice unreachable.

如果以下情况,您只能使用 @ControllerAdvice ResponseEntityExceptionHandler 您在控制器或控制器引用的任何其他bean中抛出 UsernameNotFoundException

You can only use @ControllerAdvice and ResponseEntityExceptionHandler if you are throwing UsernameNotFoundException inside controller or any others beans referenced from the controllers.

这是我的建议-您实现 AuthenticationFailureHandler 并将其与用于安全配置的 AuthenticationFilter 一起使用。
春季启动安全性带有约4个处理程序接口,用于处理与安全性相关的问题

Here is my suggestion - that you implement AuthenticationFailureHandler and use it with AuthenticationFilter that you are using for your security configuration. Spring boot security comes with about 4 handler interfaces for security related issues


  1. AccessDeniedHandler -处理诸如用户不具有所需角色时的问题。

  2. AuthenticationEntryPoint -处理诸如时的问题用户尝试在没有适当身份验证元素的情况下访问资源。

  1. AccessDeniedHandler - this handles issues like when a user not having required roles.
  2. AuthenticationEntryPoint - this handles issues like when a user tries to access a resource without appropriate authentication elements.

AuthenticationFailureHandler -处理诸如以下情况的问题找不到用户(即 UsernameNotFoundException )或身份验证提供程序内引发的其他异常。实际上,这可以处理 AccessDeniedException AuthenticationEntryPoint 未处理的其他身份验证异常。

AuthenticationFailureHandler - this handles issues like when a user is not found(i.e. UsernameNotFoundException) or other exceptions thrown inside authentication provider. In fact, this handles other authentication exceptions that are not handled by AccessDeniedException and AuthenticationEntryPoint.

AuthenticationSuccessHandler -这有助于在用户成功通过身份验证后执行重定向之类的工作。

AuthenticationSuccessHandler - this helps to do stuff like redirection after a user is successfully authenticated.

有关所有4个接口的实现,请参见以下示例代码段。请根据您的喜好自定义它们。

See the following example snippets for the implementation of all the 4 interfaces. Please customize these to your taste.


  1. AccessDeniedHandler 实现

  1. AccessDeniedHandler implementation



import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

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

@Component
public class RestAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized api access");

        //httpServletResponse.setStatus(HttpServletResponse.SC_FORBIDDEN);
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out,response);
        //mapper.writeValue(out, response);

        out.flush();
    }
}




  1. AuthenticationEntryPoint 实现

  1. AuthenticationEntryPoint Implementation



import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

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

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized access");
        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
        out.flush();
    }
}




  1. AuthenticationFailureHandler 实现

  1. AuthenticationFailureHandler implementation



package com.ibiller.webservices.security;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;

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


@Component
public class RestAuthenticationFailureHandler implements AuthenticationFailureHandler
{
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse httpServletResponse,
                                        AuthenticationException ex) throws IOException, ServletException
    {

        Map<String,Object> response = new HashMap<>();
        response.put("status","34");
        response.put("message","unauthorized access");

        httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        OutputStream out = httpServletResponse.getOutputStream();
        ObjectMapper mapper = new ObjectMapper();
        mapper.writerWithDefaultPrettyPrinter().writeValue(out, response);
        out.flush();
    }
}




  1. AuthenticationSuccessHandler 实现

  1. AuthenticationSuccessHandler implementation



import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;

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

@Component
public class RestSuccessHandler implements AuthenticationSuccessHandler {

    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException {
        Set<String> roles = 
          AuthorityUtils.authorityListToSet(authentication.getAuthorities());
        if (roles.contains("ROLE_ADMIN")) {
            //do something
        }

    }
}

这是扩展 WebSecurityConfigurerAdapter 的安全性配置,将所有内容连接在一起。

This is the Security configuration that extends WebSecurityConfigurerAdapter that connects everything together.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.OrRequestMatcher;
import org.springframework.security.web.util.matcher.RequestMatcher;

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


    private static final RequestMatcher PROTECTED_URLS = new OrRequestMatcher(
            new AntPathRequestMatcher("/v1/**"),new AntPathRequestMatcher("/admin/**")
    );

    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("/info/**");//url that will be ignored
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling()
                .accessDeniedHandler(accessDeniedHandler())
               .authenticationEntryPoint(authenticationEntryPoint())
                .and()
                .authenticationProvider(provider)
                .addFilterBefore(authenticationFilter(), AnonymousAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/v1/**").hasRole("API")
                .antMatchers("/admin/**").hasAnyRole("SUPER_ADMIN","ADMIN")
                .and()
                .csrf().disable()
                .formLogin().disable()
                .httpBasic().disable()
                .logout().disable();
    }

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

    @Bean
    RestAccessDeniedHandler accessDeniedHandler() {
        return new RestAccessDeniedHandler();
    }

    @Bean
    RestAuthenticationEntryPoint authenticationEntryPoint() {
        return new RestAuthenticationEntryPoint();
    }

    @Bean
    RestAuthenticationFailureHandler authenticationFailureHandler(){
        return new RestAuthenticationFailureHandler();
    }

    @Bean
    RestSuccessHandler successHandler(){
        return new RestSuccessHandler();
    }
}

这篇关于Spring Security如何处理UsernameNotFoundException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆