Java的Shiro框架认证流程详解

 更新时间:2024年01月04日 08:41:10   作者:Splaying  
这篇文章主要介绍了Java的Shiro框架认证流程详解,Shiro 是一个功能强大和易于使用的安全框架,为开发人员提供一个直观而全面的解决方案的认证,授权,加密,会话管理四大功能,需要的朋友可以参考下

1、Shiro框架介绍

在这里插入图片描述

  • Shiro 是一个功能强大和易于使用的安全框架,为开发人员提供一个直观而全面的解决方案的认证,授权,加密,会话管理四大功能!
  • Subject:主体,subject记录了当前操作用户,将当前登录访问的用户信息存在其中。
  • Authenticator:身份认证/登录,验证用户账号密码是否正确。
  • Authorizer:授权,根据不同的用户发放不同的权限。
  • SessionManager:会话管理,它不依赖web容器的session,因此Shiro也可以使用在非web应用上独立使用
  • Realm:领域范围,securityManager进行安全认证需要通过Realm获取数据,然后与Subject中的数据进行认证授权!
  • Cryptography:加密功能,将隐私数据进行加密。
  • SessionDAO:会话dao,是对session会话操作的一套接口,可以通过jdbc将会话数据存储到数据库。
  • CacheManager:缓存管理,Shiro提供的缓存机制;为了提高效率。

2、入门案例

2.1、项目依赖

<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.7.1</version>
</dependency>

2.2、模拟数据

  • resource/shiro.ini文件
  • 一定是ini配置文件,并且使用键值对的形式
[users]
zhangsan=123
admin=123456
splay=123456

2.3、案例

  • 可以看到Shiro最核心的东西是SecurityManager安全管理器
  • 然后初始化ini中的数据给Realm、Realm的数据正常是从数据库中获取的。
  • 将SecurityManager安全管理器注入到SecurityUtil全局工具类中
  • 最后创建令牌模拟用户登录进行校验!
  • 当用户名不正确时抛出UnknownAccountException异常、密码不对时抛出IncorrectCredentialsException异常!
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
public class Application {
    public static void main(String[] args) {
        // 1. 创建安全管理器对象
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        // 2. 给安全管理器对象设置realm(模拟数据库中的数据)
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));
        // 3. SecurityUtil设置全局的安全管理器
        SecurityUtils.setSecurityManager(securityManager);
        // 4. 关键对象Subject主体对象
        Subject subject = SecurityUtils.getSubject();
        // 5. 模拟登录(用户名、密码)
        UsernamePasswordToken user = new UsernamePasswordToken("splay", "123456");
        try{
            System.out.println("认证状态: " + subject.isAuthenticated());
            //登录校验
            subject.login(user);
            System.out.println("认证状态: " + subject.isAuthenticated());
        } catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("认证失败: 用户名密码错误!");
        } catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("认证失败: 用户名错误!");
        }
    }
}

3、源码解析

  • Shiro对整个登录用户的认证分为两个步骤:先校验用户名、其次校验密码;
  • 主要涉及三个类:AuthenticatingRealm、AuthorizingRealm、SimpleAccountRealm

3.1、用户名校验

  • 这里只校验账户名是否被锁定、证书是否过期这两项。
  • 并且这里的account返回为空是可以的。
public class SimpleAccountRealm extends AuthorizingRealm {
	protected SimpleAccount getUser(String username) {
	    USERS_LOCK.readLock().lock();				//ReentrantReadWriteLock可重入读写锁
	    try {
	        return this.users.get(username);
	    } finally {
	        USERS_LOCK.readLock().unlock();
	    }
	}
	
	protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)  {
	    UsernamePasswordToken upToken = (UsernamePasswordToken) token;
	    SimpleAccount account = getUser(upToken.getUsername());
		
	    if (account != null) {				
	        if (account.isLocked()) {		//账户被锁定
	            throw new LockedAccountException("Account [" + account + "] is locked.");
	        }
	        if (account.isCredentialsExpired()) {		//凭证过期
	            String msg = "The credentials for account [" + account + "] are expired";
	            throw new ExpiredCredentialsException(msg);
	        }
	    }
	    return account;
	}
}

3.2、密码校验

当用户校验返回值不为空时说明账户存在、没有被锁定、证书没有过期时进行密码校验。

public abstract class AuthenticatingRealm extends CachingRealm implements Initializable {

	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;
    }
    protected void assertCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) throws AuthenticationException {
        CredentialsMatcher cm = getCredentialsMatcher();
        if (cm != null) {
            if (!cm.doCredentialsMatch(token, info)) {
                // 密码错误异常
                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.");
        }
    }
}

3.3、账户不存在异常

这里调用3.2中的方法、3.2中的调用3.1;实则Shiro封装了很多层这里只是最重要的代码。

public class ModularRealmAuthenticator extends AbstractAuthenticator {
	protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) {
        if (!realm.supports(token)) {
            String msg = "Realm [" + realm + "] does not support authentication token [" +
                    token + "].  Please ensure that the appropriate Realm implementation is " +
                    "configured correctly or that the realm accepts AuthenticationTokens of this type.";
            throw new UnsupportedTokenException(msg);
        }
        AuthenticationInfo info = realm.getAuthenticationInfo(token);
        if (info == null) {
            String msg = "Realm [" + realm + "] was unable to find account data for the " +
                    "submitted AuthenticationToken [" + token + "].";
            throw new UnknownAccountException(msg);			//账户不存在
        }
        return info;
    }
}

到此这篇关于Java的Shiro框架认证流程详解的文章就介绍到这了,更多相关Shiro框架认证流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 浅析JVM的垃圾回收器

    浅析JVM的垃圾回收器

    这篇文章主要介绍了JVM垃圾回收器的相关资料,帮助大家更好的理解和学习Java虚拟机的相关知识,感兴趣的朋友可以了解下
    2020-11-11
  • Java对象深复制与浅复制实例详解

    Java对象深复制与浅复制实例详解

    这篇文章主要介绍了 Java对象深复制与浅复制实例详解的相关资料,需要的朋友可以参考下
    2017-05-05
  • Java C++题解leetcode672灯泡开关示例

    Java C++题解leetcode672灯泡开关示例

    这篇文章主要为大家介绍了Java C++题解leetcode672灯泡开关示例详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-09-09
  • SpringBoot结合dev-tool实现IDEA项目热部署的流程步骤

    SpringBoot结合dev-tool实现IDEA项目热部署的流程步骤

    这篇文章主要给大家介绍了SpringBoot结合dev-tool实现IDEA项目热部署的流程步骤,文章通过图文介绍的非常详细,对大家的学习有一定的帮助,需要的朋友可以参考下
    2023-10-10
  • Jmeter测试时遇到的各种乱码问题及解决

    Jmeter测试时遇到的各种乱码问题及解决

    这篇文章主要介绍了Jmeter测试时遇到的各种乱码问题及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • SpringBoot将Spring fox更换为Springdoc的方法详解

    SpringBoot将Spring fox更换为Springdoc的方法详解

    由于项目中使用Spring fox已经不维护更新了,代码扫描,扫出问题,需要将Spring fox更换为Spring Doc,所以本文给大家介绍了SpringBoot将Spring fox更换为Springdoc的方法,文中有相关的代码供大家参考,需要的朋友可以参考下
    2024-01-01
  • Java MyBatis 多表查询详解

    Java MyBatis 多表查询详解

    这篇文章主要给大家介绍了关于MyBatis如何实现多表查询(多对一、一对多)的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习
    2021-09-09
  • Java二维数组与稀疏数组相互转换实现详解

    Java二维数组与稀疏数组相互转换实现详解

    在某些应用场景中需要大量的二维数组来进行数据存储,但是二维数组中却有着大量的无用的位置占据着内存空间,稀疏数组就是为了优化二维数组,节省内存空间
    2022-09-09
  • 在java代码中获取JVM参数的方法

    在java代码中获取JVM参数的方法

    下面小编就为大家带来一篇在java代码中获取JVM参数的方法。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-01-01
  • 详解Struts2拦截器机制

    详解Struts2拦截器机制

    这篇文章主要介绍了详解Struts2拦截器机制,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-06-06

最新评论