Shiro -认证凭据(密码)加密的那些事

一般来说,实际项目中隐私数据没有在网络上明文跑路,都会采用不同的加密算法。Shiro中的认证凭据通常也会采用算法进行加密。

【1】CredentialsMatcher接口

该接口只有一个方法,doCredentialsMatch,就是用来进行密码比较的!

源码如下:

public interface CredentialsMatcher {

    /**
     * Returns {@code true} if the provided token credentials match the stored account credentials,
     * {@code false} otherwise.
     *
     * @param token   the {@code AuthenticationToken} submitted during the authentication attempt
     * @param info the {@code AuthenticationInfo} stored in the system.
     * @return {@code true} if the provided token credentials match the stored account credentials,
     *         {@code false} otherwise.
     */
    boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info);

}

其实现类如下:

Shiro -认证凭据(密码)加密的那些事_第1张图片

里面可以看到我们常用的MD5算法和SHA-X算法。

其中Md5CredentialsMatcher 和Sha1CredentialsMatcher 标注已经过时,通常我们会直接在容器中注册HashedCredentialsMatcher来使用!

如这里我们注册HashedCredentialsMatcher并指定算法为Md5,xml配置如下:



   
   
      
		
         
         
         
       
   


【2】盐值加密

使用【1】中的配置情况下,如果两个人的原始密码一样,那么其加密后的密码也相同,同样存在风险。

在HashedCredentialsMatcher中有这样一个方法:

 protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) {
     String hashAlgorithmName = assertHashAlgorithmName();
     return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations);
 }

其中new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations)就是根据提供的原始凭据,加密算法,盐值和加密次数进行加密并返回加密后的结果。盐值是一个唯一字符串,这里你可以使用loginName作为加密盐值。


步骤如下:

  • 在 doGetAuthenticationInfo 方法返回值创建 SimpleAuthenticationInfo 对象的时候, 需要使用SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 构造器;
  • 使用 ByteSource.Util.bytes() 来计算盐值;
  • 盐值需要唯一, 一般使用随机字符串或 user id;
  • 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 来计算盐值加密后的密码的值。

如果使用盐值加密,我们的doGetAuthenticationInfo修改如下:

	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken authenticationToken) throws AuthenticationException {
		 	UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
	        //获取页面传来的用户账号
		 	String loginName = token.getUsername();
	        //根据登录账号从数据库查询用户信息
	        SysUser user = sysUserService.getUserByLoginCode(loginName);
	        System.out.println("从数据库查询到的用户信息 : "+user);
	        //一些异常新娘西
	        if (null == user) {
	        	throw new UnknownAccountException();//没找到帐号
	        }
	        if (user.getStatus()==null||user.getStatus()==0) {
	        	throw new LockedAccountException();//帐号被锁定
	        }
	        //其他异常...
	        
	        
	        //返回AuthenticationInfo的实现类SimpleAuthenticationInfo
//	        return new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
	        //盐值加密
	        ByteSource credentialsSalt = ByteSource.Util.bytes(loginName);
	        return new SimpleAuthenticationInfo(user, user.getPassword(), credentialsSalt, this.getName());
	}

你可能感兴趣的:(#)