一、概述

前面一篇文章我们通过示例详细说明了Shiro如何进行用户身份认证的,但是我们是比对的明文密码,本篇文章将总结一下Shiro的加密功能,实现密文的比对。

如果还没有阅读前面一篇Shiro实现用户身份认证的,可以通过下面的链接进行阅读:

02、Shiro 速成:SpringBoot+Shiro 现用户身份认证功能

二、调整Shiro全局配置类

【a】Shiro全局配置类中注入HashedCredentialsMatcher密码匹配凭证管理器

/**
 * 密码匹配凭证管理器(密码加密需要此配置)
 *
 * @return
 */
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
    HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
    //加密算法
    hashedCredentialsMatcher.setHashAlgorithmName("MD5");
    // 设置加密次数
    hashedCredentialsMatcher.setHashIterations(1024);
    return hashedCredentialsMatcher;
}

【b】Shiro全局配置类中配置Realm的密码加密管理器

/**
 * 配置自定义的Realm
 *
 * @param matcher
 * @return
 */
@Bean
public MyShiroRealm myShiroRealm(HashedCredentialsMatcher matcher) {
    MyShiroRealm myShiroRealm = new MyShiroRealm();
    //配置密码加密
    myShiroRealm.setCredentialsMatcher(matcher);
    return myShiroRealm;
}

/**
 * 将Realm注册到securityManager中
 *
 * @return
 */
@Bean("securityManager")
public DefaultWebSecurityManager securityManager() {
    return new DefaultWebSecurityManager(myShiroRealm(hashedCredentialsMatcher()));
}

【c】Shiro MD5密码生成

Shiro中提供的MD5密码加密方法如下:

public SimpleHash(String algorithmName, Object source, Object salt, int hashIterations)

参数说明:

  • algorithmName:加密算法名称
  • source:需要加密的密码
  • salt:加密的盐值
  • hashIterations:需要加密的次数
public static void main(String[] args) {
    SimpleHash simpleHash = new SimpleHash("MD5", "123456", "admin", 1024);
    System.out.println(simpleHash);
}

【d】修改数据库中密码为加密后的密码

 

 

这里只是模拟密文的密码,实际生产环境中,肯定是需要前端加密再传输到后台的。

【e】修改一下自定义的Realm

由于需要将密码加密,所以需要使用复杂一点的构造方法构造SimpleAuthenticationInfo对象:

public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName)

  • 第一个字段是加密算法;
  • 第二个字段是user.getPassword(),注意这里是指从数据库中获取的password;
  • 第三个字段是盐值;
  • 第四个字段是realm,即当前realm的名称;
/**
 * 认证相关方法
 */
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) authenticationToken;
    //1.判断用户名, token中的用户信息是登录时候传进来的
    String username = usernamePasswordToken.getUsername();
    char[] password = usernamePasswordToken.getPassword();
    logger.info("username:" + username);
    logger.info("password:" + new String(password));

    //通过账号查找用户信息
    User user = userMapper.findUserByName(username);
    if (null == user) {
        logger.error("用户不存在..");
        throw new UnknownAccountException("用户不存在!");
    }
    if ("0".equals(user.getStatus())) {
        throw new LockedAccountException("账号已被锁定,请联系管理员!");
    }

    //数据库中查询的用户名
    Object principal = user.getUsername();
    Object credentials = user.getPassword();
    String realmName = getName();
    ByteSource byteSource = ByteSource.Util.bytes(username);

    //2.判断密码
    //第一个字段是加密算法
    //第二个字段是user.getPassword(),注意这里是指从数据库中获取的password。
    //第三个字段是盐值
    //第四个字段是realm,即当前realm的名称。
    //从这里传入的password(这里是从数据库获取的)和token(filter中登录时生成的)中的password做对比,如果相同就允许登录,不相同就抛出IncorrectCredentialsException异常。
    // 将账户名,密码,盐值,getName()实例化到SimpleAuthenticationInfo中交给Shiro来管理
    return new SimpleAuthenticationInfo(principal, credentials, byteSource, realmName);
}

【f】启动项目,访问:http://localhost:8080/index, 使用admin/123456进行登录。

 

可以看到,登录成功, 说明我们的MD5密码加密管理器配置的没有问题。

【g】断点Debug,观察Shiro底层比对密码的关键代码:

在UsernamePasswordToken类的getPassword()方法打上一个断点,重新进行登录。

下图是MyShiroRealm执行login之后认证方法内:

 

继续单步调试,当运行到HashedCredentialsMatcher类的doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info)方法时,此方法就是真正进行密码比对的方法:

public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
    //通过认证方法里面传入的UsernamePasswordToken对象中的密码,结合我们配置的密码加密器进行加密,生成密码1
    Object tokenHashedCredentials = this.hashProvidedCredentials(token, info);
    //通过认证方法返回值构造的SimpleAuthenticationInfo对象里面配置的密码,生成密码2
    Object accountCredentials = this.getCredentials(info);
    //将密码1和密码2进行比对,如果相等,返回true,表示认证成功,登录成功,反之认证失败。
    return this.equals(tokenHashedCredentials, accountCredentials);
}

 

 

三、总结

以上就是关于在Shiro中如何配置密码加密器进行密文密码的比对,并通过Debug方式找到了Shiro底层是如何进行比对密码的,实际工作中,肯定在前端就已经对密码加密了,然后再传输到后端由Shiro完成比对。