SpringSecurity新老密码迭代的说明
前几天给的一个需求,让兼容老版本的密码,还要可以选择加密方式
springSecurity的简单使用
新老系统的迭代,还有加密算法的随机加密
用户登录的方式–交给框架管理
package com.itheima.security;
import com.alibaba.dubbo.config.annotation.Reference;
import com.itheima.pojo.Permission;
import com.itheima.pojo.Role;
import com.itheima.pojo.SysUser;
import com.itheima.service.UserService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import java.util.ArrayList;
import java.util.List;
public class SpringSecurityUserService implements UserDetailsService {
@Reference
private UserService userService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//从数据库查询用户对象
SysUser sysUser = userService.queryByUsername(username);
if (sysUser == null) {
return null;
}
//创建权限集合
List<GrantedAuthority> list = new ArrayList<>();
//遍历角色集合
for (Role role : sysUser.getRoles()) {
list.add(new SimpleGrantedAuthority(role.getKeyword()));
//遍历角色所包含的权限集合
for (Permission permission : role.getPermissions()) {
list.add(new SimpleGrantedAuthority(permission.getKeyword()));
}
}
//包装UserDetails ,返回给权限框架
User user = new User(sysUser.getUsername(), sysUser.getPassword(), list);
return user;
}
}
xml的配置
<bean id="userDetailsService" class="com.itheima.security.SpringSecurityUserService"></bean>
<security:authentication-manager>
<security:authentication-provider user-service-ref="userDetailsService">
<security:password-encoder ref="passwordEncoder"/>
</security:authentication-provider>
</security:authentication-manager>
<security:global-method-security pre-post-annotations="enabled" />
<bean id="passwordEncoder" class="org.springframework.security.crypto.factory.PasswordEncoderFactories"
factory-method="createDelegatingPasswordEncoder"/>
更改的随机加密算法
这个地方有一个坑,不知道是不是框架的原因当使用这种加密方式的时候会出现问题,最好不是用这种加密的方式。此处的工具类我给注掉了,有大神的话可以解惑????????
encoders.put(“scrypt”, new SCryptPasswordEncoder());
//获取随机的加密对象
public static DelegatingPasswordEncoder getDelegatingPasswordEncoder(){
//获取安全框架中多种加密方式的map集合
Map<String, PasswordEncoder> encoders = new HashMap<>();
encoders.put("bcrypt", new BCryptPasswordEncoder());
encoders.put("ldap", new LdapShaPasswordEncoder());
encoders.put("MD4", new Md4PasswordEncoder());
encoders.put("MD5", new MessageDigestPasswordEncoder("MD5"));
//TODO 明文加密不使用
// encoders.put("noop", NoOpPasswordEncoder.getInstance());
encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
//TODO 这个加密方式不能使用,会报错抛异常
// encoders.put("scrypt", new SCryptPasswordEncoder());
encoders.put("SHA-1", new MessageDigestPasswordEncoder("SHA-1"));
encoders.put("SHA-256", new MessageDigestPasswordEncoder("SHA-256"));
encoders.put("sha256", new StandardPasswordEncoder());
//获取所有的Key
Set<String> keys = encoders.keySet();
ArrayList<String> passwordKeys = new ArrayList<>(keys);
//使用随机数获取索引
int index = new Random().nextInt(passwordKeys.size());
return new DelegatingPasswordEncoder(passwordKeys.get(index), encoders);
}
用户的添加加密
public Result add(Integer[] roleIds, @RequestBody SysUser user){
long count = userService.findCountByUsername(user);
if(count > 0){
return new Result(false,MessageConst.QUERY_USERNAMECOUNT_SUCCESS);
}
log.debug("=========开始添加用户============");
log.debug("roleIds :"+roleIds+","+"user :"+user);
//获取前端的密码
String password = user.getPassword();
//使用随机加密对象进行加密
DelegatingPasswordEncoder delegatingPasswordEncoder = PasswordUtils.getDelegatingPasswordEncoder();
password = delegatingPasswordEncoder.encode(password);
//更改密码
user.setPassword(password);
userService.add(roleIds,user);
log.debug("添加用户成功");
return new Result(true,MessageConst.ADD_USER_SUCCESS);
}
修改密码的时候需要手动解密
public Result editPassword( @RequestBody Map<String,String> map){
log.debug("map:"+map);
String username = map.get("username");
String password = map.get("password");
String newPassword = map.get("newPassword");
DelegatingPasswordEncoder delegatingPasswordEncoder = PasswordUtils.getDelegatingPasswordEncoder();
newPassword = delegatingPasswordEncoder.encode(newPassword);
//通过用户名查询用户的原密码
String passwordDB = userService.findPasswordByUsername(username);
//将用户输入的原密码与数据库里面的密码进行比对
boolean b = passwordEncoder.matches(password, passwordDB);
if(b){
userService.editPassword(username,newPassword);
return new Result(true,MessageConst.EDIT_PASSWORD_SUCCESS);
}else{
return new Result(false,"用户名密码校验错误");
}
}
扎心:第一次使用的时候不知道怎么兼容密码,最后才知道框架完全给解决了,扎心了,加密的时候会自动在密码之前加前缀{xxx}指定使用的加密方式,如果老版本的系统没有使用这种加密方式,如果框架里边集成了当前老版本的加密方式,直接在校验的时候手动拼接上加密方式就可以了{XXX}+密码。