Shiro:核心组件、配置类、多Realm场景、自定义拦截器、实战场景

news2024/11/15 11:20:02

目录

      • Shiro 的核心组件
      • Shiro 认证流程
      • Shiro 授权流程
      • 单 Realm
        • Shiro 登陆认证 SimpleAuthenticationInfo 对象
      • 多 Realm
      • ShiroConfig
        • Shiro过滤器配置 ShiroFilterFactoryBean
        • Shiro自定义过滤器
      • Shiro 过滤器执行链路梳理
      • 代码自取
        • 层级结构
        • Login.java
        • BearerTokenRealm.java
        • ShiroRealm.java

Shiro 的核心组件

Realm、SecurityManager、Subject

Shiro 认证流程

在这里插入图片描述
1、首先调用Subject.login(token)进行登录,其会自动委托给SecurityManager;
2、SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证;
3、Authenticator才是真正的身份验证者,Shiro API中核心的身份认证入口点,此处可以自定义插入自己的实现;
4、Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证;
5、Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。

原文链接:https://blog.csdn.net/geejkse_seff/article/details/124345585

Shiro 授权流程

待学习

单 Realm

定义一个 Realm 类继承 AuthorizingRealm,重写 授权 和 认证 两个方法,实现用户的认证授权功能。参考 Demo 代码。

Shiro 登陆认证 SimpleAuthenticationInfo 对象

认证方法中,下面的代码怎么理解:

new SimpleAuthenticationInfo(user, user.getPasswd, getName());

Shiro 会把参数一作为 Subject 主体的信息,通过下面的方式获取:

UserSession user = (UserSession) subject.getPrincipal();

Shiro 会拿 参数二 和 AuthenticationToken 中的 getCredentials() 比较,判断密码的正确性。不匹配则抛出异常。

参考文章

多 Realm

实战:多端用户登入分别认证

ShiroConfig

定义各种 Shiro 配置的 Bean:SecurityManager、DefaultWebSessionManager、ShiroFilterFactoryBean

Shiro过滤器配置 ShiroFilterFactoryBean

一些写法 和 开发注意参考

Shiro自定义过滤器

	ShiroFilterFactoryBena shiroFilter = new ShiroFilterFactoryBena();
	
	Map<String, Filter> filter = new HashMap<>();
	filters.put("authc", new MyFilter());
	shiroFilter.setFilters(filter);

	Map<String, String> filterMap = new LinkedHashMap<>();
	filterMap.put("/login", "anon");
	filterMap.put("/**", "authc");
	shiroFilter.setFilterChainDefinitionMap(filterMap);

实战,在过滤器中校验 Token

Shiro 过滤器执行链路梳理

用户登入的动作,Realm里的授权、认证动作,自定义过滤器里的动作,它们的先后顺序是怎么样的,有什么样的调用关系?

在 Shiro 的配置类中,我们通过 ShiroFilterFactoryBean 来添加过滤器,链路的梳理也要在 ShiroFilterFactoryBean 类里找答案。

Shiro过滤器执行链路梳理(认证和授权)

Shiro的Filter机制详解—源码分析

代码自取

只贴了一些核心代码,提供一些思路。

层级结构

在这里插入图片描述

Login.java

登入分为:第一次账号密码登入;之后 Token 登入

/**
 * 登陆api
 */
@RestController
@Slf4j
public class LoginApi {

    /**
     * 登录
     *
     * @param username 用户名
     * @param password 密码
     * @return 成功信息
     */
    @PostMapping("/login")
    public ResponseDTO login(String username, String password) {
	 	UsernamePasswordToken token = new UsernamePasswordToken(userId, EncrpytionUtil.encrypt(password));
        Subject subject = SecurityUtils.getSubject();
        subject.login(token);
        UserSession userSession = (UserSession) subject.getPrincipal();
        ResponseDTO loginResponse = new ResponseDTO();
        loginResponse.setInfo(userSession.getInfo());
        return loginResponse;
    }

    /**
     * 登出系统
     *
     * @return ImsTeResponse
     */
    @GetMapping("/logout")
    public ResponseDTO logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return new ResponseDTO().success();
    }
    
}

BearerTokenRealm.java

/**
 * BearerTokenRealm
 *
 */
@Component
@Slf4j
public class BearerTokenRealm extends AuthorizingRealm {

    /**
     * ICommDictEntryAppService 字典实体服务
     */
    @Autowired
    private ICommDictEntryAppService dictEntryAppService;

    /**
     * 权限service
     */
    @Autowired
    private IRoleAppService roleAppService;

    /**
     * 员工service
     */
    @Autowired
    private IOperatorAppService operatorAppService;

    /**
     * 外部系统访问授权业务层接口
     */
    private final ICommSystemAccessTokenAppService commSystemAccessTokenService;

    /**
     * 登录相关业务层接口
     */
    private final ILoginAppService loginAppService;

    /**
     * 构造方法
     *
     * @param commSystemAccessTokenService 外部系统访问授权业务层接口
     * @param loginAppService              登录相关业务层接口
     */
    @Autowired
    public BearerTokenRealm(ICommSystemAccessTokenAppService commSystemAccessTokenService,
                            ILoginAppService loginAppService) {
        this.commSystemAccessTokenService = commSystemAccessTokenService;
        this.loginAppService = loginAppService;
    }

    /**
     * 授权
     * @param authenticationToken
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        UserSession userSession = (UserSession) SecurityUtils.getSubject().getPrincipal();
        Long operatorId = userSession.getOperatorId();

        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();

        List<CommRoleResponseDTO> roleList = roleAppService.findOperatorRole(operatorId);
        Set<String> roleSet = roleList.stream().map(CommRoleResponseDTO::getRoleName).collect(Collectors.toSet());
        simpleAuthorizationInfo.setRoles(roleSet);
        return simpleAuthorizationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        UserSession userSession = (UserSession) SecurityUtils.getSubject().getPrincipal();
        if (userSession == null) {
            throw new MercuryException("用户未登入或Token已过期", 202);
        }
        String token = ((BearerToken) authenticationToken).getToken();
        UserAuthInfo userAuthInfo;
        try {
            userAuthInfo = new Gson().fromJson(TextCodec.BASE64URL.decodeToString(token),
                    UserAuthInfo.class);
        } catch (JsonSyntaxException e) {
            throw new AuthenticationException("非法请求");
        }

        Calendar minTime = Calendar.getInstance();
        minTime.add(Calendar.MINUTE, -15);
        Calendar maxTime = Calendar.getInstance();
        maxTime.add(Calendar.MINUTE, 15);
        if (userAuthInfo.get_() < minTime.getTimeInMillis()
                || userAuthInfo.get_() > maxTime.getTimeInMillis()) {
            throw new MercuryException("非法请求,token过期", 201);
        }
        String userName = userAuthInfo.getUserName();

        OperatorPO operator = operatorAppService.findByUserId(userName);
        if (operator == null) {
            throw new AuthenticationException("用户不存在!");
        }
        return new SimpleAuthenticationInfo(loginAppService.buildSessionOperator(operator), token, getName());
    }

    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof BearerToken;
    }
}

ShiroRealm.java

/**
 * shirorealm
 */
@Slf4j
public class ShiroRealm extends AuthorizingRealm {

	/**
     * 登录相关业务层接口
     */
    @Autowired
    private IOperatorAppService operatorAppService;

    /**
     * 登录相关业务层接口
     */
    @Autowired
    private ILoginAppService loginAppService;

    /**
     * 权限service
     */
    @Autowired
    private IRoleAppService roleAppService;
    
    /**
     * 
     * 授权
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        UserSession userSession = (UserSession) SecurityUtils.getSubject().getPrincipal();
        Long operatorId = userSession.getOperatorId();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        List<CommRoleResponseDTO> roleList = roleAppService.findOperatorRole(operatorId);
        Set<String> roleSet = roleList.stream().map(CommRoleResponseDTO::getRoleName).collect(Collectors.toSet());
        simpleAuthorizationInfo.setRoles(roleSet);
        return simpleAuthorizationInfo;
    }

    /**
     * 认证
     * @param authenticationToken
     * @return
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) {
        try {
            String userId = (String) authenticationToken.getPrincipal();
            String principal = String.valueOf((char[])authenticationToken.getCredentials());
            OperatorPO operator = operatorAppService.findById(userId);
            if (operator == null) {
                log.error("用户不存在!");
                throw new IncorrectCredentialsException("用户不存在!");
            }
            String passwd = "从数据库获取的用户密码";
            UserSession userSession = loginAppService.buildSessionOperator(operator);
            //new SimpleAuthenticationInfo(arg1,arg2,arg3):第一个参数是(UserSession) subject.getPrincipal()的信息;第二个参数,应该传数据库的密码,Shiro会拿 passwd 和 principal比较校验密码;参数三是当前Realm的名字
            return new SimpleAuthenticationInfo(userSession, passwd, getName());	

        } catch (IncorrectCredentialsException e) {
            throw new IncorrectCredentialsException("密码或用户名错误!");
        }
    }

	//重写supports()方法,可以在多个 Realm 场景里使用,见 CustomModularRealmAuthenticator.java
    @Override
    public boolean supports(AuthenticationToken token) {
        return token instanceof UsernamePasswordToken;
    }

}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/171698.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

桶排序详细说明及实现-python

前言&#xff1a; 说到桶排序&#xff0c;那必定要有桶&#xff0c;那么桶的作用是什么呢&#xff1f;桶的作用就是将序列分为若干份放到桶中&#xff0c;每个桶中能装入的数量范围是一定的&#xff0c;只有最后一个桶可以设置装入很多。这是因为当分的桶一定时&#xff0c;前面…

SpringMVC-基础入门

文章目录SpringMVC1&#xff0c;SpringMVC概述2&#xff0c;SpringMVC入门案例2.1 需求分析2.2 案例制作步骤1:创建Maven项目步骤2:补全目录结构步骤3:导入jar包步骤4:创建配置类步骤5:创建Controller类步骤6:使用配置类替换web.xml步骤7:配置Tomcat环境步骤8:启动运行项目步骤…

【软考】系统集成项目管理工程师(十五)项目采购管理

一、项目采购管理概述二、项目采购管理子过程1. 编制采购管理计划2. 实施采购3. 控制采购4. 结束采购三、招投标1. 招标人的权利和义务2. 招标代理机构的权利和义务3. 招标方式和招投标程序4. 相关的法律责任一、项目采购管理概述 采购意味着从外界来源获得商品或服务,采购一…

Vue3组件初始化流程分析

本文主要来分析 vue3 组件的初始化(基于runtime-core(核心运行时)包)&#xff0c;将从createApp、mount 等常用 API 入手来分析组件的挂载、普通元素的挂载流程。 createApp 1、创建一个应用实例。使用方式如下: import { createApp } from vue import App from ./App.vueco…

进制转换(二进制、八进制、十进制、十六进制)超详细版

今天来总结一下各种进制转换问题&#xff0c;详细齐全易于理解&#xff0c;希望对你有帮助哦&#xff01; 各种进制之间的相互转换 先从我们最熟悉的十进制入手吧&#xff0c;其他进制与十进制的转换方法都是一样的。 整型有4种进制形式&#xff1a; 1.十进制&#xff1a; …

[ChatGPT]

最近hatGPT火爆全宇宙&#xff0c;几乎所有圈内人都在谈论这个美国人工智能公司OpenAI发布免费机器人对话模型ChatGPT&#xff08;GPT-3.5系列&#xff09;&#xff0c;模型中首次采用RLHF&#xff08;从人类反馈中强化学习&#xff09;方式。模型目前处于测试阶段&#xff0c;…

Windows 服务器刷题(2)(带答案)

作者简介&#xff1a;一名云计算网络运维人员、每天分享网络与运维的技术与干货。 座右铭&#xff1a;低头赶路&#xff0c;敬事如仪 个人主页&#xff1a;网络豆的主页​​​​​​ 目录 前言 一.刷题 前言 本章将会讲解Windows服务器刷题&#xff08;2&#xff09; 一…

新年礼物已收到!2022 Apache IoTDB Commits 数量排名 3/351!

社区喜报&#xff01;据 The Apache Software Foundation 官方 Projects Statistics&#xff08;项目信息统计网站&#xff09;的实时数据显示&#xff0c;Apache IoTDB 在过去 12 个月&#xff08;即 2022 年度&#xff09;共发表 6829 Commits&#xff0c;排名 2022 年度 Apa…

C++ Primer笔记——默认移动操作、移动迭代器、左右值引用成员函数、标准库仿函数、function包装器

目录 一.P476 合成的移动操作 二.P480 移动迭代器 三.P483 右值和左值引用成员函数 四.P510 标准库定义的仿函数 五.P512 标准库function类型&#xff08;包装器&#xff09; 一.P476 合成的移动操作 什么时候会有默认的移动构造和移动赋值函数&#xff0c;需满足以下几点…

Java设计模式-中介者模式Mediator

介绍 中介者模式&#xff08;Mediator Pattern&#xff09;&#xff0c;用一个中介对象来封装一系列的对象交互。中介者使各个对象不需要显式地相互引用&#xff0c;从而使其耦合松散&#xff0c;而且可以独立地改变它们之间的交互。中介者模式属于行为型模式&#xff0c;使代…

linux搭建webapp实战

首先介绍下linux&#xff0c;linux因其开源&#xff0c;定制化高&#xff0c;安全等原因&#xff0c;成为了目前web应用部署首选的操作系统&#xff0c;linux操作系统有很多版本&#xff0c;常见的有centos&#xff0c;debian&#xff0c;RHLE&#xff0c;redhat&#xff0c;乌…

【Linux】gcc/g++编译器、make/Makefile自动化构建工具

作者&#xff1a;小卢 专栏&#xff1a;《Linux》 喜欢的话&#xff1a;世间因为少年的挺身而出&#xff0c;而更加瑰丽。 ——《人民日报》 目录 1.gcc/c的概念&#xff1a; 2.程序编译过程详解&#xff1a; 2.1程序编译过程&#xff1a; 2.…

微电网(风、光、储能、需求响应)【Simulink 仿真实现】

目录 1 展现 2 典型几个介绍 2.1 采用PR的三相逆变器电压控制 2.2 太阳能直流微电网系统 2.3 主电网故障时的交流微电网性能 2.4 混合光伏、双馈发电和电池能源的微电网集成 3 写在后面 4 完整资源 1 展现 随便打开一个&#xff0c;就以第一个&#xff08;采用PID的三…

【GD32F427开发板试用】macOS/Linux系统开发环境搭建(开发、编译、烧录、调试)

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动&#xff0c;更多开发板试用活动请关注极术社区网站。作者&#xff1a;HonestQiao 我日常的工作环境使用的是macOS系统或者Linux系统&#xff0c;万不得已才使用Windows。 GD32官方提供了Keil MDK-ARM和IAR两款工具…

如何使用Dx命令将jar打包成Dex,需要使用D8命令

使用dx打包的完整命令&#xff0c;将D:\ssh1.0.jar打包成MyClass.dex&#xff0c;MyClass.dex将会输出在当前CMD命令窗口的目录下。dx --dex --no-strict --min-sdk-version26 --outputMyClass.dex D:\ssh1.0.jar运行结果&#xff1a;不要使用dx命令&#xff0c;打出来的dex可以…

NestJS 项目实战 技术选型 (文末附视频)

前言 通过上一章的学习&#xff0c;我们了解了网关系统&#xff0c;并且针对要做的功能做了项目架构设计与需求拆解。 那在一个项目正式开发之前&#xff0c;我们还需要做一个技术调研&#xff0c;从开发框架、使用的工具、数据库等等进行一系列的预研&#xff0c;避免在业务…

嘿~ 基于分布式架构的技术交流社区(WhiteHoleV0.7)即将竣工!

文章目录前言项目介绍WhiteHole期望立项作者功能/模块简介用户模块问答模块社区模块博文模块Next前言 拖更&#xff0c;拖延了这么久&#xff0c;耗时超过3个月的项目&#xff0c;WhiteHoleV0.7 版本即将迎来最后的收尾工作。当然考虑到服务成本&#xff0c;和开发进度&#x…

【以太网硬件十九】SGMII到底能不能直接出光模块?

SGMII接口到底能不能直接出光模块&#xff1f;先说结论&#xff1a;我认为可以&#xff0c;但是有限制&#xff0c;此时的光口只支持强制模式&#xff0c;不支持自协商。如果对端是1000base-X接口&#xff0c;对端也需要把自协商关闭才能与SGMII直出的光口建立连接。为什么SGMI…

你是真的“C”——C语言详解求素数n种境界~

详解C语言函数模块知识(下篇&#xff09;&#x1f60e;前言&#x1f64c;必备小知识~&#x1f618;C语言详解《试除法》求解素数&#x1f64c;试除法第一层境界~ &#x1f60a;试除法境界2~&#x1f60a;试除法境界3~&#x1f60a;试除法境界4~&#x1f60a;C语言详解《筛选法》…

为何限制英伟达出售GPU芯片?中国的AI技术领先,让美国怕了

2022年下半年美国突然要求GPU芯片领军者NVIDIA停止对中国出售高端GPU芯片&#xff0c;此举让人疑惑不解&#xff0c;近期日本媒体《日本经济新闻》与荷兰的一家学术信息巨头的分析给出了答案&#xff0c;中国在AI技术上已领先于美国&#xff0c;而NVIDIA的高端GPU芯片有助于中国…