shiro登录认证

2019-1-4

片段 1片段 2片段 3片段 4片段 5片段 6


1、代码:javaConfig shiro环境

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<Long, Role> mapRole = roleService.findRoleByUserId(user.getId());
		
		List<Long> roleIds = MapUtil.toListKey(mapRole);
		//查询角色拥有的权限
		Map<Long, Permission> mapPermission = 
				permissionService.findByRoleId(roleIds);
		
		Set<String> roles = null;
		Set<String> 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);
    }

下载地址

百度网盘
密码:

相关推荐

ValidUtils.java
java

2018-12-26

java缓冲队列
java

2018-12-27