美文网首页
Spring Boot + Spring Security解决U

Spring Boot + Spring Security解决U

作者: 吴俊达 | 来源:发表于2017-03-26 22:50 被阅读5919次

    以下配置基于spring boot版本1.4.2.RELEASE,默认引入的spring security版本为4.1.3.RELEASE,页面模板采用thymeleaf。

    在MyUserDetailsService实现了UserDetailsService接口以后,在重写的loadUserByUsername方法里验证用户名不存在时,我们会抛出一个UsernameNotFoundException异常,比如:

    throw new UsernameNotFoundException("用户名不存在");
    

    但是返回页面以后, 发现并不能捕获这个异常信息,通过[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]]方式获得的异常信息始终是“Bad credentials”。

    通过程序调试发现,系统在执行到throw new UsernameNotFoundException("用户名不存在")的时候,会执行DaoAuthenticationProvider类的retrieveUser方法:

    protected final UserDetails retrieveUser(String username,
                UsernamePasswordAuthenticationToken authentication)
                throws AuthenticationException {
    
            .............................
            catch (UsernameNotFoundException notFound) {
                if (authentication.getCredentials() != null) {
                    String presentedPassword = authentication.getCredentials().toString();
                    passwordEncoder.isPasswordValid(userNotFoundEncodedPassword,
                            presentedPassword, null);
                }
                throw notFound;
            }
            ..........................
    
        }
    

    在这个方法会捕获UsernameNotFoundException异常,继续往下调试,会执行到父抽象类AbstractUserDetailsAuthenticationProvider的authenticate方法:

    public Authentication authenticate(Authentication authentication)
                throws AuthenticationException {
            
                     ....................
                catch (UsernameNotFoundException notFound) {
                    logger.debug("User '" + username + "' not found");
    
                    if (hideUserNotFoundExceptions) {
                        throw new BadCredentialsException(messages.getMessage(
                                "AbstractUserDetailsAuthenticationProvider.badCredentials",
                                "Bad credentials"));
                    }
            ..................
    
        }
    

    在这里会继续捕获到UsernameNotFoundException异常。
    由于hideUserNotFoundExceptions的值为true,所以这里会new一个新的BadCredentialsException异常抛出来,那么最后捕获到并放入session中的就是这个BadCredentialsException异常。
    所以我们在页面始终无法捕获我们自定义的异常信息。

    这里提供两个解决方案,当然可能不是最好的,希望各位同学能够给出更好的解决方案。

    第一个方案:
    1.既然系统是捕获UsernameNotFoundException类型的异常后再抛出新的BadCredentialsException异常,那么我们干脆就不抛出UsernameNotFoundException异常。
    我们模仿UsernameNotFoundException,创建自己的MyUsernameNotFoundException异常类。

    public class MyUsernameNotFoundException extends AuthenticationException {
    
        private static final long serialVersionUID = 1L;
    
        public MyUsernameNotFoundException(String msg) {
            super(msg);
        }
    
        public MyUsernameNotFoundException(String msg, Throwable t) {
            super(msg, t);
        }
    }
    

    2.在MyUserDetailsService类的loadUserByUsername方法抛出我们自己定义的MyUsernameNotFoundException异常。

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {  
            
            .....................................
            if (sysUser == null) {  
                throw new MyUsernameNotFoundException("用户名不存在");
            }  
            ....................................
        }
    

    第二个方案:
    在MyUserDetailsService类的loadUserByUsername方法直接抛出BadCredentialsException异常,这样就不需要创建自己的MyUsernameNotFoundException异常类。

    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {  
            
            .....................................
            if (sysUser == null) {  
                throw new BadCredentialsException("用户名不存在");
            }  
            ....................................
        }
    

    好了,这样在页面通过[[${session.SPRING_SECURITY_LAST_EXCEPTION.message}]],就能显示我们自定义的异常信息了。

    相关文章

      网友评论

          本文标题:Spring Boot + Spring Security解决U

          本文链接:https://www.haomeiwen.com/subject/tjqlottx.html