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框架认证流程内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot thymeleaf的使用方法解析

    SpringBoot thymeleaf的使用方法解析

    这篇文章主要介绍了SpringBoot thymeleaf的使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-03-03
  • java读取解析xml文件实例

    java读取解析xml文件实例

    这篇文章主要介绍了java读取解析xml文件实例,本文创建了一个XML解析类同时讲解了循环节点输出方式,需要的朋友可以参考下
    2015-03-03
  • java连接mongoDB并进行增删改查操作实例详解

    java连接mongoDB并进行增删改查操作实例详解

    这篇文章主要介绍了java连接mongoDB并进行增删改查操作,结合实例形式详细分析了java环境下MongoDB扩展包的下载、安装及操作MongoDB连接、增删改查等相关操作技巧,需要的朋友可以参考下
    2019-04-04
  • Springboot Mybatis Plus自动生成工具类详解代码

    Springboot Mybatis Plus自动生成工具类详解代码

    mybatis-plus 是一个 Mybatis 的增强工具,在 Mybatis 的基础上只做增强不做改变,为简化开发、提高效率而生,这篇文章带你使用Springboot Mybatis Plus自动生成工具类
    2021-11-11
  • 利用javadoc注释自动生成Swagger注解

    利用javadoc注释自动生成Swagger注解

    由于现在controller方法上面没有swagger注解,只能拿到接口url地址,无法获得接口功能描述,所以本文为大家介绍一下如何利用javadoc注释自动生成Swagger注解,感兴趣的可以了解下
    2023-08-08
  • java实现马踏棋盘算法(骑士周游问题)

    java实现马踏棋盘算法(骑士周游问题)

    这篇文章主要为大家详细介绍了java实现马踏棋盘算法,解决骑士周游问题,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-02-02
  • 解决SpringBoot整合MybatisPlus分模块管理遇到的bug

    解决SpringBoot整合MybatisPlus分模块管理遇到的bug

    这篇文章主要介绍了解决SpringBoot整合MybatisPlus分模块管理遇到的bug,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • 一文带你搞懂Java中线程的创建方式

    一文带你搞懂Java中线程的创建方式

    这篇文章主要为大家详细介绍了Java中线程的创建方式的相关知识,文中的示例代码讲解详细,具有一定的借鉴价值,感兴趣的小伙伴可以了解一下
    2023-03-03
  • jsp、servlet前后端交互对数据处理及展示的简单实现

    jsp、servlet前后端交互对数据处理及展示的简单实现

    Servlet和JSP是Java Web开发中的两个重要概念,在Servlet和JSP中前后端交互可以通过一些方式来实现,这篇文章主要给大家介绍了关于jsp、servlet前后端交互对数据处理及展示的简单实现,需要的朋友可以参考下
    2023-12-12
  • JVM工作原理和工作流程简述

    JVM工作原理和工作流程简述

    这篇文章主要介绍了关于JVM工作原理简述,主要弄清楚jvm运行的来龙去脉,感兴趣的可以一起来了解一下
    2020-07-07

最新评论