shiro笔记之----SimpleAuthenticationInfo 验证password

公司项目中用的是shiro做安全认证框架,从代码中看到了判断验证码的,也看到了判断用户名是否存在的,就是没有发现判断密码是否正确的,后从网上文章以及查看源码才大概了解shiro对于密码验证的流程。

自定义的shiroRealm

public class ShiroRealm extends AuthorizingRealm {
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
	// 第一步从token中取出用户名
		String userName = (String) token.getPrincipal();
	// 第二步:根据用户输入的userName从数据库查询
	User user = userService.findByUsername("userName");		
	if(user==null){
		return null;//用户不存在
	}
	//第三步  从数据库取该用户的passw
	String password = user.getPassword();
	// 第四步  加盐
		String salt = userCode;
		.......其他判断逻辑......
		// 第五步  创建SimpleAuthenticationInfo
		SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(user,password,ByteSource.Util.bytes(salt), this.getName());
		//第六步 返回
		return simpleAuthenticationInfo;//  return的过程完成 password的验证
}

}

注意:最后的return simpleAuthenticationInfo 的时候就会触发password验证。
我们要知道一个继承关系
shiroRealm----->AuthorizingRealm---->AuthenticatingRealm

当执行"return simpleAuthenticationInfo"之后,会调用AuthenticatingRealm的getAuthenticationInfo()方法

 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) {
        	//验证token,info的数据
            assertCredentialsMatch(token, info);
        } else {
            log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}].  Returning null.", token);
        }

        return info;
    }

上面代码中又调用了assertCredentialsMatch(token, info);

    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
        //判断验证是否通过,如果不通过则抛出异常(这个异常将在LoginController中捕获并处理)
            if (!cm.doCredentialsMatch(token, info)) {
                //not successful - throw an exception to indicate this:
                String msg = "Submitted credentials for token [" + token + "] did not match the expected credentials.";
                throw new IncorrectCredentialsException(msg);
            }
        } else {
            throw new AuthenticationException("A CredentialsMatcher must be configured in order to verify " +
                    "credentials during authentication.  If you do not wish for credentials to be examined, you " +
                    "can configure an " + AllowAllCredentialsMatcher.class.getName() + " instance.");
        }
    }

继续看doCredentialsMatch()的源码
调用的是类HashedCredentialsMatcher的方法

 public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
        Object tokenHashedCredentials = hashProvidedCredentials(token, info);//这里将得到页面传递来的password通过加密后的结果
        Object accountCredentials = getCredentials(info);//这里得到是数据库的passwrod通过加密后的结果
        return equals(tokenHashedCredentials, accountCredentials);
    }

到这里就可看到password验证的大致流程,
如果返回true,那么验证就通过了。
如何返回false,那么上面的AuthenticatingRealm.assertCredentialsMatch()方法会抛出 IncorrectCredentialsException异常
在我们的LoginController中可以看到捕获shiro中异常的代码

@Controller
public class LoginController{
	@RequestMapping(value="login")
	public String login(HttpServletRequest request)throws Exception{
	//如果登陆失败从request中获取认证异常信息,shiroLoginFailure就是shiro异常类的全限定名
		String exceptionClassName = (String) request.getAttribute("shiroLoginFailure");
		//根据shiro返回的异常类路径判断,抛出指定异常信息
		if(exceptionClassName!=null){
			if (UnknownAccountException.class.getName().equals(exceptionClassName)) {
				//最终会抛给异常处理器
				isSucCode = 1;
				errInfo = "账号不存在或已作废";
				/*throw new CustomException("账号不存在");*/
			} else if (AuthenticationException.class.getName().equals(exceptionClassName)){
				//最终会抛给异常处理器
				isSucCode = 1;
				errInfo = "账号不存在或已作废";
			}else if (IncorrectCredentialsException.class.getName().equals(
					exceptionClassName)) { 
				isSucCode = 2;
				errInfo = "密码错误";
				/*throw new CustomException("密码错误");*/
			} else if("randomCodeError".equals(exceptionClassName)){
				isSucCode = 3;
				errInfo = "验证码错误";
				/*throw new CustomException("验证码错误");*/
			}else {
				isSucCode = 4;
				errInfo = "未知错误,请联系管理员";
				/*throw new CustomException("未知错误,请联系管理员");*/
			}
		}
}

}

可以看到获取IncorrectCredentialsException异常后,提示密码错误给前段页面.

shiro-redis-spring-boot-starter是一个用于集成Apache Shiro和Redis的Spring Boot Starter项目。Apache Shiro是一个强大而灵活的Java安全框架,用于身份验证、授权和会话管理等安全功能。而Redis是一个高性能的内存数据库,其具有快速的数据存取能力和持久化支持。 shiro-redis-spring-boot-starter提供了一种简化和快速集成Shiro和Redis的方式,使得在Spring Boot应用中实现安全功能变得更加容易。通过使用该Starter,我们可以方便地将Shiro的会话管理功能存储到Redis中,从而支持分布式环境下的会话共享和管理。 使用shiro-redis-spring-boot-starter可以带来以下好处: 1. 分布式环境的会话共享:通过将Shiro的会话数据存储到Redis中,不同的应用节点可以共享同一个会话,从而实现分布式环境下的会话管理和跨节点的身份验证和授权。 2. 高可用性和性能:Redis作为一个高性能的内存数据库,具有出色的数据读写能力和持久化支持,可以提供可靠的会话存储和高性能的数据访问能力。 3. 简化配置和集成:shiro-redis-spring-boot-starter提供了封装好的配置和集成方式,减少了我们自己实现集成的复杂性和工作量。 总结来说,shiro-redis-spring-boot-starter为我们提供了一种简化和快速集成Shiro和Redis的方式,使得在Spring Boot应用中实现安全功能变得更加容易和高效。通过它,我们可以实现分布式环境下的会话共享和管理,提供高可用性和性能的数据存取能力,同时简化了配置和集成的复杂性。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值