Shiro学习

Shiro学习

什么是Shiro

Shiro是一个安全框架,可以用于认证(Authentication),鉴权(Authorizetion),加密和会话管理。

Shiro的三大核心组件

  1. Subject :当前用户的操作
  2. SecurityManager:用于管理所有的Subject
  3. Realms:用于进行权限信息的验证

Subject:即当前用户,在权限管理的应用程序里往往需要知道谁能够操作什么,谁拥有操作该程序的权利,shiro中则需要通过Subject来提供基础的当前用户信息,Subject 不仅仅代表某个用户,也可以是第三方进程、后台账户(Daemon Account)或其他类似事物。

SecurityManager:即所有Subject的管理者,这是Shiro框架的核心组件,可以把他看做是一个Shiro框架的全局管理组件,用于调度各种Shiro框架的服务。

Realms:Realms则是用户的信息认证器和用户的权限人证器,我们需要自己来实现Realms来自定义的管理我们自己系统内部的权限规则。

Shiro的登录认证流程

使用的subject.login(usernamePasswordToken)完成登录。完成登录后,subject虽然为Shiro库里的实现,
但是subject.getPrincipal()返回的数据类型却为用户的自定义类型UserInfo2?

下面为业务侧登录代码:

@PostMapping("/loginUser")
public String loginUser(@RequestParam("login_name") String login_name,
@RequestParam("password") String password
, HttpSession session, Model model) {
    try {
        System.out.println("loginUser: " + login_name + ":" + password);
        UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(login_name, password);
        Subject subject = SecurityUtils.getSubject();
        subject.login(usernamePasswordToken); //完成登录
        UserInfo2 user = (UserInfo2) subject.getPrincipal();
        session.setAttribute(Constant.CURRENT_USER, user);
        return "redirect:index";
    } catch (Exception e) {
        model.addAttribute("result", "用户名或密码错误");
        return "html/login";
    }
}

Shiro的认证流程源代码查看

在前面登录时,会传入认证令牌token(传入的为UsernamePasswordToken), 再看UsernamePasswordToken类的实现,token.getPrincipal()返回的为username。 之后产生新对象SimpleAuthenticationInfo, 传入的第一个参数为UserInfo2的对象,作为principal存储在内部,所以上面subject.getPrincipal()获取的对象为UserInfo2对象,SimpleAuthenticationInfo中保存的是数据库中正确的user和password。并返回新产生的authenticationInfo。那么登录的用户名密码和数据库的用户名密码是在哪里比对的呢?

@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    String loginname = (String) token.getPrincipal();

    UserInfo2 user = userService.findByLoginName(loginname);

    if (user == null) {
        throw new UnknownAccountException();//没找到帐号
    }

    SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, //用户
            user.getPassword(), //密码
            getName() //realm name
    );
    return authenticationInfo;
}

在AuthenticatingRealm中, 有doGetAuthenticationInfo函数上层函数调用流程
代码:

    public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        AuthenticationInfo info = getCachedAuthenticationInfo(token);
        if (info == null) {
            //otherwise not cached, perform the lookup:
            info = doGetAuthenticationInfo(token);
            log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
            if (token != null && info != null) {
                cacheAuthenticationInfoIfPossible(token, info);
            }
        } else {
            log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
        }

        if (info != null) {
            assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }

继续跟进代码,在assertCredentialsMatch内部有调用HashedCredentialsMatcher::doCredentialsMatch

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

在这里可以看到根据数据库查询结果info和页面传入值token对比。

在Shiro配置代码中有配置密码比对管理器

    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        log.info("hashedCredentialsMatcher()");
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();

        hashedCredentialsMatcher.setHashAlgorithmName("MD5");// 散列算法:这里使用MD5算法;
        hashedCredentialsMatcher.setHashIterations(1024);// 散列的次数,比如散列两次,相当于
        // md5(md5(""));

        return hashedCredentialsMatcher;
    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值