美文网首页
2019-01-10 springboot + spring-s

2019-01-10 springboot + spring-s

作者: FredWorks | 来源:发表于2019-01-10 16:07 被阅读0次

在后台,如果用户名登录错误,是有返回具体的错误异常信息的。但是在前台界面,却只看到了“Bad Credential”,而不是具体错误信息。
仔细跟踪代码,发现问题处在这里:

org.springframework.security.core.userdetails.UsernameNotFoundException: 用户名不正确
    at cn.fredworks.security.service.authen.AuthenService.loadUserByUsername(AuthenService.java:66) ~[classes/:na]
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:104) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationProvider.java:144) ~[spring-security-core-5.0.6.RELEASE.jar:5.0.6.RELEASE]

这段代码中,抛出的异常,被 AbstractUserDetailsAuthenticationProvider 拦截了:

    public Authentication authenticate(Authentication authentication)
            throws AuthenticationException {
        Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
                messages.getMessage(
                        "AbstractUserDetailsAuthenticationProvider.onlySupports",
                        "Only UsernamePasswordAuthenticationToken is supported"));

        // Determine username
        String username = (authentication.getPrincipal() == null) ? "NONE_PROVIDED"
                : authentication.getName();

        boolean cacheWasUsed = true;
        UserDetails user = this.userCache.getUserFromCache(username);

        if (user == null) {
            cacheWasUsed = false;

            try {
                user = retrieveUser(username,
                        (UsernamePasswordAuthenticationToken) authentication);
            }
            catch (UsernameNotFoundException notFound) {
                logger.debug("User '" + username + "' not found");

                if (hideUserNotFoundExceptions) {
                    throw new BadCredentialsException(messages.getMessage(
                            "AbstractUserDetailsAuthenticationProvider.badCredentials",
                            "Bad credentials"));
                }
                else {
                    throw notFound;
                }
            }

            Assert.notNull(user,
                    "retrieveUser returned null - a violation of the interface contract");
        }

重点是其中的:

            catch (UsernameNotFoundException notFound) {
                logger.debug("User '" + username + "' not found");

                if (hideUserNotFoundExceptions) {
                    throw new BadCredentialsException(messages.getMessage(
                            "AbstractUserDetailsAuthenticationProvider.badCredentials",
                            "Bad credentials"));
                }
                else {
                    throw notFound;
                }
            }

如果 AbstractUserDetailsAuthenticationProvider 的属性 hideUserNotFoundExceptions 被设置为 true 了,就会隐藏原始的错误信息,而该属性的默认值就是 true。

我们在实际上,使用的是 AbstractUserDetailsAuthenticationProvider 的子类 DaoAuthenticationProvider。只要在spring-security配置时,设置其 hideUserNotFoundExceptions 为 false,就解决问题了。
我们可以这样,在javaconfig的配置类中,做如下处理:

@Configuration
public abstract class XxxModuleSecurityConfig extends WebSecurityConfigurerAdapter {

    @Resource(name = SecurityModuleBeanNames.SecurityModuleAuthenService)
    private UserDetailsService userDetailService;
    
    /**
     * 构建自定义的DaoAuthenticationProvider
     * @return
     */
    @Bean
    public DaoAuthenticationProvider daoAuthenticationProvider() {
        DaoAuthenticationProvider bean = new DaoAuthenticationProvider();
        bean.setHideUserNotFoundExceptions(false);
        bean.setUserDetailsService(this.userDetailService);
        bean.setPasswordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence rawPassword) {
                try {
                    return CodecUtils.string2Md5String(rawPassword.toString());
                } catch (Exception e) {
                    throw new BadCredentialsException("调用加密算法对密码进行加密时异常", e);
                }
            }

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                if (StringUtils.isBlank(rawPassword)) {
                    throw new BadCredentialsException("没有提供密码");
                } else if (StringUtils.isBlank(encodedPassword)) {
                    throw new BadCredentialsException("系统中密码密文是空白字符串");
                } else {
                    return this.encode(rawPassword).equals(encodedPassword);
                }
            }
        });
        
        return bean;
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(this.daoAuthenticationProvider());
    }

处理到这里后,发现系统返回具体错误信息了,但仍然有问题,中文“用户名错误”是乱码。显然是因为spring-boot默认没有设置UTF-8编码所致。
在application.properties中设置如下:

# setting charset utf-8
spring.http.encoding.force=true
spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
server.tomcat.uri-encoding=UTF-8

服务重启后发现,乱码已经没有了

相关文章

网友评论

      本文标题:2019-01-10 springboot + spring-s

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