最近在內建sping security 到spring boot中,看到大部分登陸驗證的代碼都這麼寫
@Service
public class CustomUserService implements UserDetailsService { //自定義UserDetailsService 接口
@Autowired
UserDao userDao;
@Autowired
PermissionDao permissionDao;
public UserDetails loadUserByUsername(String username) {
SysUser user = userDao.findByUserName(username);
if (user != null) {
List<Permission> permissions = permissionDao.findByAdminUserId(user.getId());
List<GrantedAuthority> grantedAuthorities = new ArrayList <>();
for (Permission permission : permissions) {
if (permission != null && permission.getName()!=null) {
GrantedAuthority grantedAuthority = new SimpleGrantedAuthority(permission.getName());
grantedAuthorities.add(grantedAuthority);
}
}
return new User(user.getUsername(), user.getPassword(), grantedAuthorities);
} else {
throw new UsernameNotFoundException("admin: " + username + " do not exist!");
}
}
}
然後配置那時的代碼為:
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(urlUserService).passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return MD5Util.encode((String) rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return encodedPassword.equals(MD5Util.encode((String) rawPassword));
}
});
}
看到以上代碼,我就有個疑問了。
loadUserByUsername是為什麼要把使用者的權限也擷取了呢,如果密碼不正确,那擷取的權限也沒有用,浪費性能。
個人調試了一下代碼,發現登陸驗證時,确實會調用到loadUserByUsername。
那怎麼辦呢?如何解決。
經查,解決辦法如下;
1.不使用UserDetailsService,改為使用AbstractUserDetailsAuthenticationProvider
示例代碼如下:
public class MucAppAuthenticationProvider extends
AbstractUserDetailsAuthenticationProvider {
private static Logger logger = LoggerFactory.getLogger(AbstractUserDetailsAuthenticationProvider.class);
@Autowired
SecurityUserService securityUserService;
@Override
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
//如果想做點額外的檢查,可以在這個方法裡處理,校驗不通時,直接抛異常即可
}
@Override
protected UserDetails retrieveUser(String username,
UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
//擷取使用者權限或密碼校驗
return loadUserDetail(username);
}
}
2.配置WebSecurityConfigurer改為如下:
@Bean
AppAuthenticationProvider appAuthenticationProvider() { // 注冊UserDetailsService 的bean
return new AppAuthenticationProvider();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(appAuthenticationProvider());
}
經測試,登陸驗證沒有發現任何問題