Shiro 加盐加密

2018-11-09  本文已影响0人  风吟空城

开头一段废话

加盐加密会使用户的密码受到相对安全的保护,比普通的MD5加密要好。用户数据暴露给了用户,因为有盐值的存在,也很难拿到用户的原始密码。即时拿到了,也会增加破解难度。

Shiro权限框架有加盐加密的实现,下面就简单描述下自己实现的过程。

盐值

我使用的盐值是32的随机字符串,盐值越长,保密性相对越好。不过,有看到其他开发者说24位的盐值是考虑加密速度等因素后比较合适的。

工具类

public class ShiroUtil {

    /**
     * 生成32的随机盐值
     */
    public static String createSalt(){
        return UUID.randomUUID().toString().replaceAll("-", "");
    }

    /**
     * 加盐加密
     * @param srcPwd    原始密码
     * @param saltValue 盐值
     */
    public static String salt(Object srcPwd, String saltValue){
        return new SimpleHash("MD5", srcPwd, saltValue, 1024).toString();
    }

}

方法作用见注释,此处不做说明。

后端加密

本人采用的方案是在后端加密。即在创建用户时,生成随机盐值,然后将加密后的密码存入数据库。如:

public class User {
    /**
     * ID
     */
    private String id;

    /**
     * 登录用户
     */
    @NotEmpty(message = "用户名:用户名不能为空")
    private String username;

    /**
     * 登录密码
     */
    @Length(min = 6, message = "密码:密码长度不能低于6位")
    @NotEmpty(message = "密码:密码不能为空")
    private String password;

    /**
     * 盐值
     */
    private String saltValue;

    /**
     * 手机号
     */
    private String mobile;

    /**
     * 昵称
     */
    private String nickname;

    /**
     * 是否冻结
     */
    private Integer isFrozen;

    /**
     * 创建时间
     */
    private Date createTime;

    public User() {
    }

    public User(String id, String username, String password, String saltValue, String mobile, String nickname,
                Integer isFrozen, Date createTime) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.saltValue = saltValue;
        this.mobile = mobile;
        this.nickname = nickname;
        this.isFrozen = isFrozen;
        this.createTime = createTime;
    }

    /**
     * 创建新的用户
     * @param username 用户名
     * @param password 密码
     * @param nickname 昵称
     * @param mobile   手机号
     */
    public static User createUser(String username, String password, String nickname, String mobile){
        String saleValue = ShiroUtil.createSalt();
        return new User(ShiroUtil.createSalt(), username, ShiroUtil.salt(password, ByteSource.Util.bytes(saleValue).toString()),
                saleValue, mobile, nickname, 0, new Date());
    }
    //省略set/get方法
}

@NotEmpty等注解,采用的thymeleaf的表单校验,如果报错了,请删除该注解,或者在POM中引入依赖即可,如:

<dependency>
  <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>

Shiro认证

用户加密完成后,在Shiro中认证时,加盐加密用户输入的密码,然后和库中的对比是否一致即可。如:

public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserMapper userMapper;


    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //todo:获取用户的权限
        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;

        User user = this.userMapper.selectByPrimaryKey(token.getUsername());
        if (user == null){
            throw new AuthenticationException("用户不存在!");
        }
        //盐值
        ByteSource salt = ByteSource.Util.bytes(user.getSaltValue());
        String saltPassword = ShiroUtil.salt(token.getPassword(), salt.toString());
        if (!user.getPassword().equals(saltPassword)){
            throw new AuthenticationException("输入密码不正确!");
        }
        if (user.getIsFrozen() == 0){
            throw new AuthenticationException("用户已冻结!");
        }
        //第4个参数是realm名称
        return new SimpleAuthenticationInfo(token.getPrincipal(), token.getPassword(), salt, getName());
    }

}
上一篇 下一篇

猜你喜欢

热点阅读