security遇java.lang.IllegalArgumentException Cannot pass null or empty values toconstructor

x33g5p2x  于2022-02-12 转载在 Java  
字(3.2k)|赞(0)|评价(0)|浏览(379)

1.遇到这个报错大概都是因为在实现UserDetailService接口,执行查库操作发现有null值

2.确定null值的字段

在测试类中

//注入Mapper
@Autowired
private UserMapper userMapper;
@Test
void contextLoads() {
    //调用方法
    System.out.println(userMapper.getUserByPhoneNumber("1"));
}
//打印的结果
User{phoneNumber='null', password='1'}

发现数据库的字段phoneNumber为空值,能查出password,但phoneNumber找不到。

最后了解发现,在数据库表中的字段带有_,比如phone_number,在实体类中,如果你使用小驼峰需要在Yaml这样配置开启小驼峰规则

mybatis: 
 	configuration:
      map-underscore-to-camel-case: true

还有一步就是在Mapper中加入

@Select("select phone_number,password from customer where phone_number=#{phoneNumber}")
@Result(column = "phone_number",property = "phoneNumber",jdbcType = JdbcType.VARCHAR)
Customer getUserByPhoneNumber(String phoneNumber);

3.More

在security中加入自己的验证规则可以实现AuthenticationProvide接口

public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        SmsCodeAuthenticationToken smsCodeAuthenticationToken = (SmsCodeAuthenticationToken) authentication;
        /**
        * 我的用户实体类实现了UserDetailer接口,userDetailsService也有我自己的实现类。
        *所有要使用security框架,进行查库操作用户实体类和XXXUserDetailService需要实现相应的接口才能把自己的规则加入到Security中
        */
       
        UserDetails user = userDetailsService.loadUserByUsername((String)smsCodeAuthenticationToken.getPrincipal());
        //用户user为空说明,数据库中查不到
        if(user == null){
            throw new InternalAuthenticationServiceException("用户不存在");
        }
        //下面是验证在数据库中查到的密码和用户输入的密码是否相同
        if(!new BCryptPasswordEncoder().matches(smsCodeAuthenticationToken.getCredentials().toString(),user.getPassword())){
            throw new BadCredentialsException("密码不正确");
        }
        //进入到SmsCodeAuthenticationToken类,将用户和用户权限存到SmsCodeAuthenticationToken对象中
        SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(user,user.getAuthorities());
        authenticationResult.setDetails(smsCodeAuthenticationToken.getDetails());
        return authenticationResult;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return SmsCodeAuthenticationToken.class.isAssignableFrom(aClass);
    }

    public UserDetailsService getUserDetailsService() {
        return userDetailsService;
    }

    public void setUserDetailsService(UserDetailsService userDetailsService) {
        this.userDetailsService = userDetailsService;
    }

}

SmsCodeAuthenticationToken类

public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
    private final Object principal;
    private  Object credentials;

    public SmsCodeAuthenticationToken(String mobile,String password) {
        super(null);
        this.principal = mobile;
        this.credentials=password;
        setAuthenticated(false);
    }

    public SmsCodeAuthenticationToken(Object principal,
                                      Collection<? extends GrantedAuthority> authorities) {
        super(authorities);
        this.principal = principal;
        super.setAuthenticated(true); // must use super, as we override
    }

    public Object getCredentials() {
        return this.credentials;
    }

    public Object getPrincipal() {
        return this.principal;
    }

    public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
        if (isAuthenticated) {
            throw new IllegalArgumentException(
                    "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
        }

        super.setAuthenticated(false);
    }

    @Override
    public void eraseCredentials() {
        super.eraseCredentials();
    }
}

相关文章