极简入门,Shiro的认证与授权流程解析

Springboot基础学习之(十七):通过Shiro实现用户得到登录认证和授权 springboot项目:通过shiro实现用户的认证和授权服务 设置网页的访问权限,不同的网页是具有不同的权限的用户才能够访问的 阅读详情
小Hub领读:

接下来的几天,我们开讲Shiro,从入门到分析、集成、单点登录整合等几篇。今天我们先来认识一下Shiro吧~


其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了:

  • 登陆、授权流程

  • shiro过滤器链

  • 整合Springboot、redis做共享会话

  • 结合xxl-sso实现单点登录

接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登录授权逻辑。

Shiro简介

在Web系统中我们经常要涉及到权限问题,例如不同角色的人登录系统,他操作的功能、按钮、菜单是各不相同的,这就是所谓的权限。

而构建一个互联网应用,权限校验管理是很重要的安全措施,这其中主要包含:

  • 用户认证 - 用户身份识别,即登录

  • 用户授权 - 访问控制

  • 密码加密 - 加密敏感数据防止被偷窥

  • 会话管理 - 与用户相关的时间敏感的状态信息

Shiro对以上功能都进行了很好的支持,它可以非常容易的开发出足够好的应用。Shiro可以帮助我们完成:认证、授权、加密、会话管理、与Web集成、缓存等。而且Shiro的API也是非常简单。

官方源码:https://github.com/apache/shiro

整体结构与重要组件

从上图可以看出,Security Manager是Shiro的核心管理器,认证授权会话缓存等都是在其内部完成,然后会委托给具体的组件来处理,比如认证过程委托给Authenticator,授权委托给Authorizer组件。所以,整理还是比较清晰,源代码也容易追踪。

我们来具体聊聊所有的组件:

Subject:主体,可以看到主体可以是任何可以与应用交互的“用户”;

SecurityManager:Shiro的心脏;所有具体的交互都通过SecurityManager进行控制;负责所有Subject、且负责进行认证和授权、及会话、缓存的管理。

  • Authenticator:认证器,判断用户是否正常登陆

  • Authorizer:授权器,判断用户是否有权限操作资源

Realm:可以有1个或多个Realm,主要提供认证和授权的数据;

Session:Shiro提供一个权限的企业级Session解决方案,session的生命周期都在SessionManager中进行管理。

SessionManager:shiro的会话管理器;

SessionDAO:用于会话的CRUD,比如存储到ehcache或者redis中的会话增删改查;

CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少去改变,放到缓存中后可以提高访问的性能

Cryptography:密码模块,Shiro提高了一些常见的加密组件用于如密码加密/解密的。

官方简单示例

官网例子:http://shiro.apache.org/tutorial.html

刚入门Shiro的同学,真的需要去看看这个官方例子,你可以更加深入了解Shiro的权限校验流程。我还是贴一下代码吧,一些同学比较懒:

  • shiro.ini

# -----------------------------------------------------------------------------
# Users and their (optional) assigned roles
# username = password, role1, role2, ..., roleN
# -----------------------------------------------------------------------------
[users]
root = secret, admin
guest = guest, guest
presidentskroob = 12345, president
darkhelmet = ludicrousspeed, darklord, schwartz
lonestarr = vespa, goodguy, schwartz
# -----------------------------------------------------------------------------
# Roles with assigned permissions
# roleName = perm1, perm2, ..., permN
# -----------------------------------------------------------------------------
[roles]
admin = *
schwartz = lightsaber:*
goodguy = winnebago:drive:eagle5

上面代码中, root=secret,admin表示,用户名root,密码secret,角色是admin; schwartz=lightsaber:*表示角色schwartz拥有权限lightsaber:*。你其实可以把这个文件看成一个Realm,其实就是shiro默认的IniRealm。

  • 测试类Tutorial

public class Tutorial {
    private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);
    public static void main(String[] args) {
        log.info("My First Apache Shiro Application");
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // get the currently executing user:
        Subject currentUser = SecurityUtils.getSubject();
        // Do some stuff with a Session (no need for a web or EJB container!!!)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }
        // let's login the current user so we can check against roles and permissions:
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }
        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
        //test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }
        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }
        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }
        //all done - log out!
        currentUser.logout();
        System.exit(0);
    }
}

从上面的实例中,我们可以总结一下常用的API:

常用API
#获取当前用户
Subject currentUser = SecurityUtils.getSubject(); 
#判断用户已经认证
currentUser.isAuthenticated() 
#用户登录凭证
UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); 
#记住我
token.setRememberMe(true); 
#登陆校验
currentUser.login(token); 
#判断是否有角色权限
currentUser.hasRole("schwartz") 
#判断是否有资源操作权限
currentUser.isPermitted("lightsaber:wield") 
#登出
currentUser.logout();

其实稍微梳理一下,可以发现上面代码主要有两个步骤:

  • 认证:

UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
currentUser.login(token);
currentUser.logout();
  • 判断权限

currentUser.hasRole("schwartz")
currentUser.isPermitted("winnebago:drive:eagle5")

接下来,我们去探讨一下shiro的认证与授权流程,并从源码层去解析一下shiro各个组件之间的关系。

认证流程

上面图片中,根据序号,其实我们大概能猜出里shiro的认证流程:

  1. Subject进行login操作,参数是封装了用户信息的token

  2. Security Manager进行登录操作

  3. Security Manager委托给Authenticator进行认证逻辑处理

  4. 调用AuthenticationStrategy进行多Realm身份验证

  5. 调用对应Realm进行登录校验,认证成功则返回用户属性,失败则抛出对应异常

我们从login方法开始debug一下流程,用简要方式追踪shiro源码的认证逻辑:

currentUser.login(token);
|
Subject subject = this.securityManager.login(this, token);
|
AuthenticationInfo info = this.authenticate(token);
|
this.authenticator.authenticate(token);
|
AuthenticationInfo info = this.doAuthenticate(token);
|
Collection<Realm> realms = this.getRealms();
doSingleRealmAuthentication(realm, token);
|
AuthenticationInfo info = realm.getAuthenticationInfo(token);
|
AuthenticationInfo info = realm.doGetAuthenticationInfo(token);

ok,一条线下来,从login到委托给authenticator,再最后调用realm的doGetAuthenticationInfo方法。

所以,从源码上来看,如果要实现shiro的认证逻辑,至少要准备一个Realm组件、和初始化securityManager组件。

常见异常
  • DisabledAccountException(禁用的帐号)

  • LockedAccountException(锁定的帐号)

  • UnknownAccountException(错误的帐号)

  • ExcessiveAttemptsException(登录失败次数过多)

  • IncorrectCredentialsException (错误的凭证)

  • ExpiredCredentialsException(过期的凭证)

授权流程

从上图中,我们可以知道授权流程如下:

  • 调用Subject.isPermitted/hasRole接口

  • 委托给SecurityManager

  • 而SecurityManager接着会委托给Authorizer

  • Authorizer会判断Realm的角色/权限是否和传入的匹配

  • 匹配如isPermitted/hasRole会返回true,否则返回false表示授权失败

追踪一下源码如下:

currentUser.hasRole("schwartz")
|
this.securityManager.hasRole(this.getPrincipals(), roleIdentifier)
|
this.authorizer.hasRole(principals, roleIdentifier)
|
AuthorizationInfo info = this.getAuthorizationInfo(principal);
return info.getRoles().contains(roleIdentifier)
|
info = this.doGetAuthorizationInfo(principals);(realm)

所以shiro判断用户是否有权限首先会从realm中获取用户所拥有的权限角色信息,然后再匹配当前的角色或权限是否包含,从而判定用户是否有权限!

说到权限,很多人自然会想起权限系统,涉及到几个关键对象:

  • 主体(Subject)

  • 资源(Resource)

  • 权限(Permission)

  • 角色(Role)

通过这几个要素,可以设计出比较合理的权限系统。

Shiro常见3种授权判断方式:
  • 编码实现

Subject subject = SecurityUtils.getSubject();  
if(subject.hasRole(“admin”)) {  
    //有权限  
} else {  
    //无权限  
}
  • 注解实现

@RequiresRoles("admin")  
public void hello() {  
    //有权限  
}  
  • JSP Taglig实现,freemarker等类似

<shiro:hasRole name="admin">  
<!— 有权限 —>  
</shiro:hasRole>  

jsp页面引入shiro标签

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags"%>

在线会话管理

获取当前会话总人数
@Autowired
private SessionDAO sessionDAO;
//获取会话数量
int size = sessionDAO.getActiveSessions().size()
强制下线
//强制退出
Session session = sessionDAO.readSession(subject.getSession().getId());
sessionDAO.delete(session);
// logout,可作为强制退出
subject.logout();
Assert.isTrue(!subject.isAuthenticated());

结束语

ok,感觉是高度极简的一篇文章,主要把重要的组件和登录、授权几个流程搞清楚之后,其实shiro基本已经学会了,后面我们再学一下shiro的几个主要内置过滤器怎么使用,如何集成SpringBoot,基本就差不多了。


(完)

MarkerHub文章索引:(点击阅读原文直达)
https://github.com/MarkerHub/JavaIndex
【推荐阅读】
面试官: HashMap 为什么线程不安全?
Spring cache整合Redis,并给它一个过期时间!
月薪10K、15K、20K的Java程序员分别需要掌握哪些技术?
传统@ServerEndpoint方式开发WebSocket应用和SpringBoot构建WebSocket应用程序
小白教程,Springboot项目搭建(前端到数据库,超详细)

好文!必须点赞

Shiro中的认证和授权流程是怎样的? 【代码】Shiro中的认证和授权流程是怎样的? 阅读详情

相关推荐

Shiro认证流程和授权流程

认证:身份验证,即在应用中谁能证明他就是他本人。一般提供如他们的身份ID一些标识信息来表明他就是他本人,如提供身份证,用户名/密码来证明。 在shiro中,用户需要提供principals (身份)和credentials(证明)给shiro,从而应用能验证用户身份: principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。一个主体可以有多个principals

Emma_Joans的博客 1万+

Shiro的认证和授权过程

认证:是一个身份验证的过程,要证明他们的身份,需要提供principals(身份)和credentials(凭证)。身份有多种,包括邮箱,账号等能表示subject身份的信息,凭证有密码,指纹,数字证书等。一般就是登录,获取账号和密码。 认证过程主要分为三步: step1:收集subject的principals(身份)和credentials(凭证) 1.首先拿到当前currentUser, Subject currentUser = SecurityUtils.getSubject(); 1.1利用c

weixin_44736853的博客 2474

快速上手Shiro—Java认证和授权框架

文章以官方指南为基础,包括快速上手,Shiro的架构以及如何使用Springboot整合Shiro实现简单登录认证Shiro的架构 快速入门 环境搭建 QuickStrat.java Springboot整合Shiro 两种方式引入Shiro依赖 Shiro登录原理 Shiro核心配置类 自定义Realm类 ShiroConfig类

6790

Shiro过滤器配置(ShiroFilterFactoryBean)

这篇博客就是记录一下shiro过滤器的配置和一些注意事项 /** * Shiro过滤器配置 */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shiroFilter() { ShiroFilterFactoryBean shiroFilter = new Shir...

霓虹深处 4万+

shiro授权的实现原理

主要介绍了shiro授权的实现原理,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

python——体育收入排行2012-2019

请分析文件并读取数据,完成以下功能: 1. 某年的收入排名前若干名选手 如果输入n是2012-19之间的年份,则可以输入整数k,输出n年的前k名排名信息。如果k大于当年排名运动员人数,则输出当年所有的信息。每行一名运动员信息,以' | '间隔该行各项信息。 2. 某年属于某个运动项目的所有运动员信息,和收入总和 如果输入的是'sport'(不区分大小写),则可以继续输入一个年份201*,输出一个当年排行中的运动项目菜单,按照字符串升序排列,格式见示例,再输入运动项目对应的数字来输出该项运动当

m0_62488776的博客 2260

shiro session_极简入门,Shiro的认证与授权流程解析

Cat哥领读:接下来的几天,我们开讲Shiro,从入门到分析、集成、单点登录整合等几篇。今天我们先来认识一下Shiro吧~其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了:登陆、授权流程shiro过滤器链整合Springboot、redis做共享会话结合xxl-sso实现单点登录接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登...

weixin_39940688的博客 434

从ISO 17987到SAE J2602:LIN一致性测试标准全景解读与CANoe实现

本文深入解析了从ISO 17987到SAE J2602的LIN一致性测试标准技术演进,详细对比了两大标准体系的技术差异,并基于Vector CANoe平台演示了如何构建符合最新行业要求的自动化测试方案。文章重点介绍了SAE J2602标准的三大改进点,包括唤醒特性、传输层协议和诊断服务的增强测试要求,并提供了CANoe测试环境配置、测试模块集成及测试案例解析的实战指南。

app77的博客 338

shiro 单点登录_极简入门,Shiro的认证与授权流程解析

接下来的几天,我们开讲Shiro,从入门到分析、集成、单点登录整合等几篇。今天我们先来认识一下Shiro吧~其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了:登陆、授权流程shiro过滤器链整合Springboot、redis做共享会话结合xxl-sso实现单点登录接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登录授权逻辑。Shiro简...

weixin_39582737的博客 536

sap 新增科目表_SAP系统中四大科目表的总结

操作科目表定义-OB13 2国家科目表定义-OB13 3集团科目表定义-OB13 4合并科目表(ECCS)定义-CX10 4分配操作科目表到公司代码-OB62 5分配国家科目表到公司代码-OB62 6分配集团科目表到操作科目表-OB13 6分配集团科目表到合并科目表-CXNF 7Operation 8定义集团科目表的科目-FSP0 8定义国家科目表的科目-FSP0 8定义操作科目表的科目-FSP0...

weixin_39585463的博客 1722

LabVIEW与三菱PLC通讯实战:ActiveX控件在FX5U上的应用技巧

本文深入探讨了如何利用三菱MX Component中的ActiveX控件,在LabVIEW中实现与FX5U系列PLC的高效、稳定通讯。文章从环境配置、ActiveX控件生命周期管理、数据读写性能优化及容错机制等实战角度,分享了构建工业级健壮通讯程序的核心技巧与架构设计思路。

qsc9012345的博客 890

root认证失败 tera term_极简入门,Shiro的认证与授权流程解析

接下来的几天,我们开讲Shiro,从入门到分析、集成、单点登录整合等几篇。今天我们先来认识一下Shiro吧~其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了:登陆、授权流程shiro过滤器链整合Springboot、redis做共享会话结合xxl-sso实现单点登录接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登录授权逻辑。Shiro简...

weixin_42514432的博客 197

【技术解析】AlexNet——从ReLU到Dropout的深度学习关键突破

本文深入解析AlexNet在深度学习领域的关键突破,重点探讨了ReLU激活函数和Dropout技术的革命性应用。作为卷积神经网络的里程碑,AlexNet通过ReLU解决梯度消失问题,利用Dropout有效防止过拟合,为现代深度学习模型奠定了重要基础。这些创新技术至今仍在计算机视觉和自然语言处理等领域发挥重要作用。

weixin_33719619的博客 274

shiro分布式控制登录状态_极简入门,Shiro的认证与授权流程解析

小Hub领读:接下来的几天,我们开讲Shiro,从入门到分析、集成、单点登录整合等几篇。今天我们先来认识一下Shiro吧~其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了:登陆、授权流程shiro过滤器链整合Springboot、redis做共享会话结合xxl-sso实现单点登录接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登录授权逻辑...

weixin_36094492的博客 212

嵌入式面试|MCU+RTOS技术栈——面试八股文整理3:STM32

stm32

weixin_44800059的博客 1910

使用SIMD思想进行memcpy的优化

arm64平台的memcpy的性能优化,相比C库提升30~40%,SIMD优化思路

zhaoxin1989的博客 1万+

Shiro - 理解 Shiro 源码 剖析认证授权的核心流程

本文深入剖析Apache Shiro安全框架的认证与授权核心流程。从架构设计出发,解析Subject、SecurityManager、Realm等核心组件的协作机制,详细跟踪login()方法的源码执行路径,揭示认证过程中Authenticator与Realm的交互逻辑。通过分层递进的源码分析,帮助开发者掌握Shiro的安全原理,为实际项目中的权限系统设计与问题排查提供理论基础。

千淘万漉虽辛苦,吹尽狂沙始到金 1万+

MinerU 系列教程 | 第二课:快速上手 -- 安装与第一次解析

本篇教程作为的第二课,将带你从零完成 MinerU 的环境搭建、模型下载,并成功运行第一次文档解析。上一课我们从宏观视角认识了 MinerU,本课开始正式动手实践。

weixin_43674738的博客 304

认证授权示例——JWT及Shiro

1、常见的认证机制 1.1 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的usernamepassword,简言之,Basic Auth是配合RESTful API 使用的最简单的认证方式,只需提供用户名密码即可,但由于有把用户名密码暴露给第三方客户端的风险,在生产环境下被使用的越来越少。因此,在开发对外开放的RESTful API时,尽量...

qqxhb 资源共享 3253

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

TMS_WebGMaps_1.9.8.0_Full_Source

TMS_WebGMaps_1.9.8.0_Full_Source 全源码 delphi cbuilder

SpringBoot与Shiro整合(认证、授权和密码加密)

Shiro01_SpringBoot与Shiro整合 创建SpringBoot项目,选择以下工具包: Lombok Spring Web Thymeleaf MySQL Driver 添加MybatisPlus的依赖: <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-boot-starter</artifactId> <version

BLU_111的博客 5万+

汉书HE8,好用的汇编代码编写工具

汉书HE8,好用的汇编代码编写工具早期编写汇编代码所用功能强大

Shiro的认证与授权流程解析

极简入门,Shiro的认证与授权流程解析 其实Shiro框架并不难,我梳理了一下,你只需要学会以下内容基本就足够了: 登陆、授权流程 shiro过滤器链 整合Springboot、redis做共享会话 结合xxl-sso实现单点登录 接下来我会分为几篇文章分别去介绍,这篇我们先来了解一下shiro的一些基础知识,以及登录授权逻辑。 Shiro简介 在Web系统中我们经常要涉及到权限问题,例如不同角色的人登录系统,他操作的功能、按钮、菜单是各不相同的,这就是.

qq_39845279的博客 744

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

Shiro框架2——shiro的认证+shiro的授权

通过分析源码可得:认证:1.最终执行用户名比较是 在SimpleAccountRealm类 的 doGetAuthenticationInfo 方法中完成用户名校验2.最终密码校验是在 AuthenticatingRealm类 的 assertCredentialsMatch方法 中总结:认证realm授权realm自定义Realm的作用:放弃使用.ini文件,使用数据库查询。

qq_64064246的博客 1834
上一篇: 这篇 ReentrantLock 看不懂,加我我给你发红包
下一篇: 小匠,我朋友,从三本走进了阿里,佩服他!
Java思维导图
博客等级 码龄10年 306粉丝 71原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值