1、代码:javaConfig shiro环境 public class ConfigShiro {public void simpleDbCOnfig(){DefaultSecurityManager securityManager = new DefaultSecurityManager();Realm realm = new MyRealm();securityManager.setRealm(realm);SecurityUtils.setSe
public class ConfigShiro {
public void simpleDbCOnfig(){
DefaultSecurityManager securityManager =
new DefaultSecurityManager();
Realm realm = new MyRealm();
securityManager.setRealm(realm);
SecurityUtils.setSecurityManager(securityManager);
}
}
2、代码:生成盐,存到数据库中,salt我们也存到数据库中,解密时会取出
public void saltTest(){
//所需加密的参数 即 密码
String pwd = "123";
//[盐] 一般为用户名 或 随机数
String salt = "shiro";
//加密次数
int hashIterations = 1;
/*调用org.apache.shiro.crypto.hash.SimpleHash.SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)
* 构造方法实现盐值加密 String algorithmName 为加密算法 支持md5 base64 等*/
SimpleHash sh = new SimpleHash("md5", pwd, salt, hashIterations);
//打印最终结果,或将其存入数据库
System.out.println(sh.toHex());
}
3、代码:MyRealm(加盐)
package com.amiu.shiro.chapter5;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import com.amiu.mybatisTest.autoMybatis.SqlSessionHelper;
import com.amiu.shiro.db.User;
import com.amiu.shiro.db.UsersDao;
public class MyRealm extends AuthorizingRealm {
//操作数据库的类
@Autowired
RoleService roleService;
@Autowired
PermissionService permissionService;
@Autowired
UserDao userDao;
//设置盐解析,这里要和生成盐的设置相同,使用MD5,解密次数1次
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
//HashedCredentialsMatcher是shiro提供的解析盐的实现类
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");
matcher.setHashIterations(1);
super.setCredentialsMatcher(matcher);
}
//处理权限的,将角色Role和权限Permission存入shiro中
@Override
protected AuthorizationInfo doGetAuthorizationInfo(
PrincipalCollection principals) {
// 获取当前登录对象
User user = (User) principals.getPrimaryPrincipal();
//查询拥有角色
Map
mapRole = roleService.findRoleByUserId(user.getId());
List
roleIds = MapUtil.toListKey(mapRole); //查询角色拥有的权限 Map
mapPermission = permissionService.findByRoleId(roleIds); Set
roles = null; Set
stringPermissions = null; try { //将需要的字段转换为Set格式,name是实体类Role的字段 roles = MapUtil.toSet(mapRole, "name"); stringPermissions = MapUtil.toSet(mapPermission, "name") ; } catch (Exception e) { //这里是MapUtil工具类捕捉的异常 e.printStackTrace(); } SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); //将角色与权限放入SimpleAuthorizationInfo对象 authorizationInfo.setRoles(roles); authorizationInfo.setStringPermissions(stringPermissions); //返回给shiro return authorizationInfo; } //处理身份验证 @Override protected AuthenticationInfo doGetAuthenticationInfo( AuthenticationToken token) throws AuthenticationException { UsernamePasswordToken userToken = (UsernamePasswordToken) token; //获取当前需要登录的用户 String name = userToken.getUsername(); //从数据库获取是否有对应的用户 User user = userDao.selectByName(name); if(user == null){ //不存在用户 throw new UnknownAccountException(); } //从数据库中获取账户锁定信息 if(user.isIs_lock()){ //账户被锁定 throw new LockedAccountException(); } //从数据库中取出盐 String salt = user.getPassword_salt(); //从数据库中取出密码,密码是加过盐的 String password = user.getPassword(); //转换为byte类型的盐 ByteSource byteSalt = ByteSource.Util.bytes(salt); //返回对象,上面我们设置过的盐解析类:HashedCredentialsMatcher //会帮我们解析盐,然后验证密码是否匹配 SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, password.toCharArray(), byteSalt, getName()); return info; } @Override public String getName() { return "myRealm"; } }
4、代码:登陆测试
@Test
public void saltLogin(){
new ConfigShiro().simpleDbCOnfig();
Subject subject = SecurityUtils.getSubject();
//页面用户“li”输入的密码是明文“123”
UsernamePasswordToken token =
new UsernamePasswordToken("li","123");
try {
subject.login(token);
} catch (UnknownAccountException unknownAccountEx) {
//处理无此用户
}catch(IncorrectCredentialsException wrongPasswordEx){
//处理用户名或密码不正确
}catch(LockedAccountException lockedAccountEx){
//账户被锁定
} catch ( AuthenticationException ae ) {
//不期望出现的错误 error?
}
Assert.assertTrue(subject.isAuthenticated());
}
5、解析:MyRealm
1、登陆测试中的:
UsernamePasswordToken token = new UsernamePasswordToken("li","123");
执行subject.login(token)后,这个token传到了MyRealm中的方法:
//处理身份验证
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
这里的参数(AuthenticationToken token)即是我们的登陆用户“li”的token
2、我们自定义的Realm,我们一般选择继承shiro的AuthorizingRealm。
3、MyRealm中的返回值:
SimpleAuthenticationInfo info =
new SimpleAuthenticationInfo(user,
password.toCharArray(), byteSalt, getName());
SimpleAuthenticationInfo的第一个参数我么可以放入我们想要放入才参数,如这里的对象User,我们还能存入id
或Username等等,这个参数体现在本类处理权限的方法中:
//处理权限
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals)
这里的参数(PrincipalCollection principals)就是我们传入的对象User,我们可以这么使用它:
User User = (User) principals.getPrimaryPrincipal();
获取User对象后我们可以去数据库中查询权限信息,并加载到shiro中
6、解析:MyRealm中的重写方法setCredentialsMatcher()
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
super.setCredentialsMatcher(credentialsMatcher);
}
1、CredentialsMatcher字面意思简单理解就是[用户匹配器],作用就是匹配密码,检查
[登录密码]是否等于[数据库中查询的密码]
2、CredentialsMatcher的默认实现是SimpleCredentialsMatcher,作用是简单匹配密码,
当匹配[登录密码:123],[数据库中查询的密码:123]时,才会成功。
当匹配[登录密码:123],[数据库中加密的密码:1f45e9afefc5e28edbcbdfae08a1f7a6]时,
是不会成功的;SimpleCredentialsMatcher作用其实也就是简单判等。
上面的setCredentialsMatcher()等同于:
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
SimpleCredentialsMatcher matcher = new SimpleCredentialsMatcher();
super.setCredentialsMatcher(matcher);
}
3、当我们需要匹配加盐的密码时,就不能使用SimpleCredentialsMatcher了,我们一般使用
HashedCredentialsMatcher,HashedCredentialsMatcher可以匹配[登录明文密码]与[数据库加密密码]
但是我们必须为其指定匹配规则,也就是密码加密时的加密规则,HashedCredentialsMatcher将按照
此规则解密[数据库加密密码],然后再匹配[登录明文密码],如:
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
matcher.setHashAlgorithmName("md5");//设置解密算法为:md5
matcher.setHashIterations(1);//设置解密次数为1次
super.setCredentialsMatcher(matcher);
}
