看了网上很多教程,都提到有配置spring shiro的密码加密方式,甚至给出了自定义的Class来实现。却很少有通过配置来解决的。
密码的盐值加密方式应该是非常通用的,也可以算是基础吧。按理说spring shiro不可能没有实现,让用户自己去实现吧。
通过读源码看各种关系,摸索出shiro的MD5盐值加密方式,分享一下 (shiro的maven仓库中的source从来都是个空文件,github上的源码又没有stable版本的代码,要调试很恼火),当然阅读源码可以直接到github上,https://github.com/apache/shiro
关于shiro的基础使用这里就不贴配置了,相关文章可以自己搜索。先贴出MD5盐值加密相关配置:
<bean id="jdbcRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm">
<property name="dataSource" ref="tbDataSource" />
<property name="credentialsMatcher" ref="passwordMatcher" />
<property name="authenticationQuery"
value="select u.user_password,u.salt from auth_sys_user u where u.user_nick = ? and u.status=0" />
<property name="userRolesQuery"
value="select r.role_id from auth_user_role r where r.user_id = (select u.user_id from auth_sys_user u where u.user_nick = ? and u.status=0)" />
<property name="permissionsQuery"
value="SELECT p.permission_code FROM auth_role_permission p WHERE p.role_id = ? " />
<property name="permissionsLookupEnabled" value="true" />
<property name="saltStyle" value="COLUMN" />
</bean>
<bean id="passwordMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="MD5"/>
<property name="hashIterations" value="2"/>
</bean>
解释一下:
①credentialsMatcher属性是认证匹配的方式,这个属性使用org.apache.shiro.authc.credential.HashedCredentialsMatcher的方式。HashedCredentialsMatcher是Hash认证匹配的方式,阅读源码发现这个类有4个属性hashAlgorithm 、hashIterations 、hashSalted 、storedCredentialsHexEncoded。
其中hashAlgorithm表示hash算法名称,String类型,常见的有MD2、MD5、SHA1、SHA256、SHA384、SHA512等。
hashIterations表示hash迭代的次数,int类型,也就是加密次数,默认是1次。
hashSalted表示hash是否加盐,boolean类型,这个属性已经被标为过期,不建议使用,实际上这个属性在Realm的配置中已决定。
storedCredentialsHexEncoded表示是否存储散列后的密码为16进制(HEX),boolean类型,默认为true,否则将会以base64编码。
②saltStyle配置为COLUMN表示salt从数据库字段中获取,这时候相应的authenticationQuery查询结果,第一个字段为password,第二个字段就是salt。除此之外,saltStyle还有几个可选值,分别为NO_SALT、CRYPT、EXTERNAL。其中NO_SALT表示没有盐值;CRYPT表示salt值存在unix的加密文件中;EXTERNAL表示salt并不存在数据库中,而是通过调用JdbcRealm.getSaltForUser(username)方法得到,这个方法其实就是返回username。
当然,实现了密码的MD5盐值加密之后,在插入用户、修改用户密码的时候,就需要用同样的算法对密码进行处理,包括生成salt入库等。
对于在程序中生成加密后的密码,可以参考以下代码:
Md5Hash hash = new Md5Hash(password,salt,2);
return hash.toString();
当然,你也可以用SimpleHash,通过第一个参数指定加密算法名称(与credentialsMatcher 中配置的相同):
SimpleHash hash = new SimpleHash("MD5", password,salt,2);
return hash.toString();
对于生成随机的salt,可以使用shiro自带的SecureRandomNumberGenerator生成,如下:
private String generateSalt(){
SecureRandomNumberGenerator secureRandom = new SecureRandomNumberGenerator();
String hex = secureRandom.nextBytes(3).toHex(); //一个Byte占两个字节,此处生成的3字节,字符串长度为6
return hex;
}