在Shiro之前的版本中,密码加密一般采用如下代码:
String digestString = new Sha256Hash(password, salt, numIterations).toBase64();
密码比对一般采用HashedCredentialsMatcher或Sha256CredentialsMatcher等相关比对类,在新版1.2中,增添了一项重要的功能就是密码服务,使得加密和比对更加方便。
比如:
加密就只需要密码这个参数PasswordService svc = new DefaultPasswordService();
svc.encryptPassword(password);
比对就用如下语句:encrypted是密文
svc.passwordsMatch(password, encrypted);
看到上述代码,一个感觉就是:程序逻辑很清晰。
同样的,在1.2中,同样可以通过密码服务配置,实现与jdbc中的密码密文进行比对。直接上代码了:
以下是shiro.ini
passwordService = org.apache.shiro.authc.credential.DefaultPasswordService
passwordMatcher = com.helloweb.shm.PasswordMatcherEx
passwordMatcher.passwordService = $passwordService
ds = com.mysql.jdbc.jdbc2.optional.MysqlDataSource
ds.serverName = 192.168.1.101
ds.user = root
ds.password =******
ds.databaseName = helloweb
ds.url = jdbc:mysql://192.168.1.101:3306/helloweb
jdbcRealm = org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.permissionsLookupEnabled = true
jdbcRealm.authenticationQuery = SELECT password FROM user WHERE username = ?
jdbcRealm.dataSource = $ds
jdbcRealm.credentialsMatcher = $passwordMatcher
authc.loginUrl=/login.jsp
[urls]
/admin/**=authc
说明,com.helloweb.shm.PasswordMatcherEx是我对org.apache.shiro.authc.credential.PasswordMatcher进行了修正,重写了getStoredPassword()方法,如下:
package com.helloweb.shm;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.credential.PasswordMatcher;
public class PasswordMatcherEx extends PasswordMatcher {
@Override
protected Object getStoredPassword(AuthenticationInfo storedAccountInfo) {
Object stored = super.getStoredPassword(storedAccountInfo);
if (stored instanceof char[]) {
stored = String.valueOf((char[]) stored);
}
return stored;
}
}
重写的原因是,JdbcRealm返回给PasswordMatcher的哈希值被保存为char[]型,而PasswordMatcher 却希望getCredentials()返回一个String或Hash。
用户登录代码如下:
public String doLogin() {
Subject currentuser = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username,
password);
try {
if (currentuser.isAuthenticated())
currentuser.logout();
currentuser.login(token);
return SUCCESS;
} catch (Exception e) {
addActionError("用户名或密码有误");
return ERROR;
}
}
用户注册代码如下:
public String doReg() {
if (isLegal()) {
User user = new User();
PasswordService svc = new DefaultPasswordService();
String encrypted = svc.encryptPassword(password);
user.setUsername(username);
user.setPassword(encrypted);
UserDAO ud = new UserDAO();
if (!ud.findByUsername(username).isEmpty()) {
addActionError("用户名已存在!");
return ERROR;
}
ud.save(user);
addActionMessage("注册成功!");
} else {
addActionError("注册信息填写有误!");
return ERROR;
}
return SUCCESS;
}