自定义Realm认证的原理

1 篇文章 0 订阅

先看下简单的自定义Realm认证主体身份

package com.hxkj.commons.shiro.realm;

import com.hxkj.dao.UserDao;
import com.hxkj.vo.UserVO;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/** 自定义认证授权的Realm实现AuthorizingRealm的认证和授权的2个方法
 * Create by wangbin
 * 2019-04-03-16:35
 */
public class AuthRealm extends AuthorizingRealm {
    @Resource
    private UserDao userDao;

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取用户名
        String userName = (String) principals.getPrimaryPrincipal();
        // 从数据库或缓存中获取角色数据
        Set<String> roles = getRolesByUserName(userName);
        //从数据库或缓存中获取权限信息
        Set<String> permissions = getPermissionsByUserName(userName);
        //创建授权对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        //设置角色和权限信息
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);
        //返回授权对象就会对主体拥有的角色和权限进行校验
        return authorizationInfo;
    }

    //从数据库或缓存中获取角色信息
    private Set<String> getRolesByUserName(String userName) {
        System.out.println("从数据库中获取角色权限数据");//测试代码
        List<String> list = userDao.queryRolesByUserName(userName);
        Set<String> sets = new HashSet<>(list);
        return sets;
    }
    //从数据库或缓存中获取权限信息
    private Set<String> getPermissionsByUserName(String userName) {
        List<String> list = userDao.queryPermissionsByUserName(userName);
        Set<String> sets = new HashSet<>(list);
        return  sets;
    }

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //1.从主体登录时传过来的token中获取主体提交的用户名
        String userName = (String) token.getPrincipal();
        //2.通过主体提交的用户名去数据库中获取凭证(通过用户名获得密码)
        String password = gerPasswordByUserName(userName);//此处模拟从数据库中获得密码
        if(password==null){
            return null;
        }
        //创建认证对象
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(userName,password,"AuthRealm");
        //凭证返回之前设置盐(ByteSource.Util.bytes方法将字符串转成ByteSource对象)
        authenticationInfo.setCredentialsSalt(ByteSource.Util.bytes(userName));
        //返回凭证的时候就会对密码进行校验,通过就认证成功,密码不匹配就认证失败
        //realm中注入的加密器会在返回时将用户在页面输入的密码按照加密规则加密后与authenticationInfo
        //中查到的密码匹配,匹配成功则密码验证成功
        return authenticationInfo;
    }
    //数据库或缓存中获取凭证
    private String gerPasswordByUserName(String userName) {
        UserVO user = userDao.getUserByUserName(userName);
        if (user != null){
            return user.getPassword();
        }
        return null;
    }

    public static void main(String[] args) {
        //md5加密并设置加密次数和盐,打印加密后的字符串设置到数据库中,用于匹配验证
        Md5Hash md5Hash = new Md5Hash("123456","bin",2);
        System.out.println(md5Hash.toString());
    }
}

在自定义的Realm中返回return new SimpleAuthenticationInfo()对象这里打上断点,进行调试,会看到进入了shiro包下的HashedCredentialsMatcher这个类,里面调用了doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)这个方法,比对token和info,token中的密码是用户提交的明文密码,会调用加密器中的加密方法和次数,再从info中获取盐值,没有盐值则不获取,对token中的明文密码进行加密,得到tokenHashedCredentials 这个对象,然后获取info中的accountCredentials对象
如果这两个对象是相等的就会返回true,即主体的身份验证成功

关键代码:HashedCredentialsMatcher中的比对token和info的方法

public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    Object tokenHashedCredentials = hashProvidedCredentials(token, info);
    Object accountCredentials = getCredentials(info);
    return equals(tokenHashedCredentials, accountCredentials);
}

身份验证关键调试截图:
图中,token的凭证(明文加密后的密码)与用户的凭证(数据库中的加密密码)
完全一致,返回true,身份验证成功。
在这里插入图片描述
在这里插入图片描述
数据库中的用户加密密码
在这里插入图片描述
对比成功后返回true,主体的身份校验就玩成了

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值