当前位置: 首页 > 知识库问答 >
问题:

如何处理UsernameNotFoundException Spring Security性

孙德本
2023-03-14

如何处理UsernameNotFoundException

在spring security中,当未找到用户名时,UserDetailsService实现抛出UserNameNotFoundException。例如如下所示:

   @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实现中实现了一个处理程序方法处理程序:

  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

如有任何建议将不胜感激。很多很多问候:)。

共有1个答案

宋飞掣
2023-03-14

安全层位于控制器和@controlleradvice中的任何内容之前。因此,@controlleradvice不是一个选项,因为UsernameNotFoundExceptionAuthenticationException的子类,它在身份验证过程中引发,使@controlleradvice中的异常处理程序无法访问。

只有在controller或从controller引用的任何其他bean内部抛出UsernameNotFoundException时,才能使用@ControllerAdviceResponseEntityExceptionHandler

我的建议是:实现authenticationfailurehandler并将其与用于安全配置的authenticationfilter一起使用。Spring boot security提供了大约4个处理程序接口来解决与安全相关的问题

>

  • AccessDeniedHandler-这将处理用户不具有必需角色等问题。
  • authenticationentrypoint-这将处理用户试图访问没有适当身份验证元素的资源时的问题。

    authenticationfailurehandler-这将处理找不到用户(即UsernameNotFoundException)或在身份验证提供程序内部引发的其他异常等问题。实际上,这处理了AccessDeniedExceptionAuthenticationEntryPoint未处理的其他身份验证异常。

    authenticationsuccesshandler-这有助于在成功验证用户身份后执行重定向等操作。

    有关所有4个接口的实现,请参阅以下示例片段。请按您的口味定制这些。

    1. AccessDeniedHandler实现
    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();
        }
    }
    
    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();
        }
    }
    
    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();
        }
    }
    
    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的安全配置。

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

  •  类似资料:
    • 问题内容: Java中有没有办法处理收到的SIGTERM? 问题答案: 是的,您可以向注册一个关闭挂钩。

    • 问题内容: 我收到此错误消息: 当我将其复制到浏览器地址字段中时,它显示了正确的页面,这是有效的,但是我不能用以下方法对其进行解析: 我试过了:,但是 这不是我需要的网址 也不行 如何处理呢? 坦率 问题答案: 对字符使用编码,即。

    • 问题内容: 我是遵循Java教程的Java初学者。 我正在使用Java教程的 “ 数据流”页面中的简单Java程序,并在运行时一直显示。我想知道这是否正常,因为读者最终必须走到文件末尾。 编译正常,但输出为: 在Java教程的 “ 数据流页面”中,它显示: 注意,DataStreams通过捕获EOFException而不是测试无效的返回值来检测文件结束条件。DataInput方法的所有实现都使用E

    • 我正在为一个鼠标悬停工作,我想通过使用for loop单击每个链接来测试所有链接的工作状态。在我的程序中,迭代进行了一次,而下一次迭代却不工作了,并且显示“StaleElementReferenceException”..........如果需要,请修改代码....

    • 神话这个词有时候意味着虚构。但这有着更深层的内涵。它也意味着一些宗教内容来解释宇宙和人类与之的关系。管理者倾向于忘记他们作为一个程序员时学到的东西,并且相信某种传说。试着让他们相信这种传说是错的,正如让一个虔诚的宗教信徒从他们的信仰中醒悟过来一样粗鲁而失败。因此,你应该认可这些信仰: 文档越多越好。(他们需要文档,但他们不会想要你在这些东西上花时间。) 程序员是平等的。(程序员可以按重要程度分类。

    • 问题内容: 我正在尝试构建一个托管在Google AppEngine上的Go后端,Angular前端的应用程序,如果您没有会话或会话的登录状态为=1,则会强制您登录/ login。 我还尝试对几乎所有内容使用App Engine的app.yaml路由。 我不确定这可能吗? 目录结构: app.yaml应用程序:myapp版本:1运行时:go111#api_version:go1主程序:./serv

    • 关于,endpoint文档说明: 当web套接字会话创建了某种未在web套接字协议中建模的错误时,开发人员可能会实现此方法。例如,这可能是传入消息太大而无法处理的通知,或者传入消息无法被编码。 此方法(当前)定义要处理的异常有许多类别: 如果发生错误,方法是否应该关闭websocket(调用)? 到目前为止,我认为我的责任是干净利落地关闭会话,并将关闭的原因告知客户。这就是为什么如果返回true,

    • foo(8073)调用foo(8074) foo(8074)调用foo(8075),foo(8075) foo(8074)记录自身并调用bar(8075), foo(8074)死亡,foo(8073)捕获它,记录自己并调用bar(8074) bar(8074)调用bar(8075),bar(8074)死亡,因此bar(8074)记录自己 从所有方法返回,并优雅地关闭 我明白了,一切都很好。所以有一