Shiro认证框架

目录

概述

认证授权及鉴权

Shiro框架的核心组件

基本流程

spring boot+shiro+mybatisPlus+...实现用户登录

step1:准备工作

(1)坐标

(2)连接数据库

(3)JavaBean

(4)dao数据访问层

 (5)密码工具类 DigestsUtil

 (6)配置类

step2:认证功能

step3:授权鉴权


概述

shiro是apache下一个开源框架,它将软件系统的安全认证功能抽离出来,组成一个通用的安全认证框架,其功能主要有身份认证,授权鉴权,会话管理等功能。

认证授权及鉴权

对于认证授权及鉴权,可以通过这样一个例子来理解,比如说我买了一张去国外的机票,现在要登机,那我在取机票的时候,出示的身份证就是认证的过程,工作人员在核实你确实是本人之后,会把机票给你,这个就是授权,当你拿着张机票去登记的时候,工作人员还要查你的机票,看你是不是我这个航班的机票,这个就是鉴权。理解之后,再看下面的概念就很具体了。

身份认证是指判断一个用户是否为合法用户的过程,最常用的身份认证方式是系统通过判断用户输入的用户名密码和数据库中存储的用户名密码是否一致。由此确认该用户是否为合法用户。

授权也叫访问控制,它是指控制谁能够访问哪些资源。用户认证成功后,系统会为其分配对应的权限,访问资源时,会校验其是否有权限访问这个校验的过程就是鉴权

Shiro框架的核心组件

  • Subject(主体)

即外部应用与subject进行交互,subject将用户作为当前操作的主体,这个主体:可以是一 个通过浏览器请求的用户,也可能是一个运行的程序 。比如说我今天要做一个登录功能的认证,那我的Subject就是当前登录的用户。

  • SecurityManager(权限管理器)

权限管理器是Shiro的核心,负责管理所有Subject并通过Authenticator完成认证,以及Authorizer完成授权。

  • Authenticator(认证器)

登录时进行身份认证

  • Authorizer(授权器)

当用户通过认证,访问资源时,对用户们进行授权操作

  • Realm(数据源)

Realm用于完成数据库的读取,并在其中完成授权校验相关操作

基本流程

1、首先调用Subject.isPermitted/hasRole接口,其会委托给SecurityManager。

2、SecurityManager接着会委托给内部组件Authorizer;

3、Authorizer再将其请求委托给我们的Realm去做;Realm才是真正干活的;

4、Realm将用户请求的参数封装成权限对象。再从我们重写的doGetAuthorizationInfo方法中获取从 数据库中查询到的权限集合。

5、Realm将用户传入的权限对象,与从数据库中查出来的权限对象,进行一一对比。如果用户传入的 权限对象在从数据库中查出来的权限对象中,则返回true,否则返回false。 进行授权操作的前提:用户必须通过认证。

OK,理论结束,实践开始。。。。

spring boot+shiro+mybatisPlus+...实现用户登录

step1:准备工作

在这一部分需要先搭建一个项目的基本框架,与数据库的交互以及数据库表。在数据库方面一共需要五张表,表的结构在级联查询中已经提到,这里不再赘述,链接附在这里CSDN

 需要特别关注一点的是,对于表中密码这部分的数据,我使用sha-1算法进行了加密,一部分原因是为了安全系数更高些,另一部分原因是shiro框架支持多种算法,例如sha系列算法,以及md5Hash,md2Hash,在这里刚好也使用一下。

(1)坐标

首先需要搭建一个springBoot 项目,然后添加需要的坐标,比如数据持久层的mybatisPlus,管理javaBean的lombok,以及shiro框架相关坐标

 <properties>
        <java.version>1.8</java.version>
        <shiro.version>1.3.2</shiro.version>
    </properties>

 <dependencies>
        <!--mybatis-->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.3</version>
        </dependency>
        <!--mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.28</version>
        </dependency>
        <!--lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.28</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-web</artifactId>
            <version>${shiro.version}</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>${shiro.version}</version>
        </dependency>
    </dependencies>
(2)连接数据库

在resource资源文件下的application.properties文件中配置4想数据库连接的基本信息

(3)JavaBean

作用:ORM架构中的O,与数据库表中的字段进行一一对应。

在数据库中我们设计了5张表,但在实体类这里,不涉及关系表,关系表只在查数据的时候使用,比如我在判断该用户有没有某种权限的时候,根据登录用户输入的用户名查询用户的基本信息,拿着基本信息中的id查询用户权限,这个时候就需要使用到关系表,

 

(4)dao数据访问层

数据的交互基于两个查询操作,一个是查询基本信息也就是user表总的信息,另一个是查询详细信息,包括角色信息和权限信息

 

 (5)密码工具类 DigestsUtil

作用:获取明文密码的密文和盐值,这是由于数据库中没有数据,需要先造几条数据供使用

对于输入的明文,在获取密文密码前需要先获取盐值,所以调用generateSalt方法生成随机的盐值密文。其次调用show方法进行加密。然后存到map集合中进行返回,到这里我们需要做的就是把数据存到数据库中。

public class DigestsUtil {
//确定要使用的加密算法
    public static final String SHA1 = "SHA-1";
//加密次数
    public static final Integer COUNTS =369;

    /**
     * @Description sha1方法,根据明文和盐值进行加密
     * @param input 需要散列字符串
     * @param salt 盐字符串
     * @return
     */
    public static String show(String input, String salt) {
        return new SimpleHash(SHA1, input, salt,COUNTS).toString();
    }

    /**
     * @Description 随机获得salt字符串
     * @return
     */
    public static String generateSalt(){
        SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();
        return randomNumberGenerator.nextBytes().toHex();
    }


    /**
     * @Description 生成密码字符密文和salt密文
     * @param
     * @return
     */
    public static Map<String,String> entryptPassword(String passwordPlain) {
        Map<String,String> map = new HashMap<>();
        String salt = generateSalt();
        String password =show(passwordPlain,salt);
        map.put("salt", salt);
        map.put("password", password);
        return map;
    }

    public static void main(String[] args) {
//用户测试数据
        String name = "xixi";
        String pwd = "12345";
        Map map = entryptPassword(pwd);
        System.out.println(map.toString());

    }
}
 (6)配置类

作用:定义shiro框架的基本配置,包括拦截规则,登录页面等等,具体功能在方法上有备注

@Configuration
public class ShiroConfiguration {

    /**
     * 1.创建shiro自带cookie对象
     */
    @Bean
    public SimpleCookie sessionIdCookie(){
        SimpleCookie simpleCookie = new SimpleCookie();
        simpleCookie.setName("ShiroSession");
        return simpleCookie;
    }

    //2.创建自定义的realm,用于登录认证和授权
    @Bean
    public MyRealm getRealm() {
        return new MyRealm();
    }

    /**
     * 3.创建会话管理器
     */
    @Bean
    public DefaultWebSessionManager sessionManager(){
        DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
        sessionManager.setSessionValidationSchedulerEnabled(false);
        sessionManager.setSessionIdCookieEnabled(true);
        sessionManager.setSessionIdCookie(sessionIdCookie());
        sessionManager.setGlobalSessionTimeout(3600000);
        return sessionManager;
    }

    //4.创建安全管理器
    @Bean
    public SecurityManager defaultWebSecurityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(getRealm());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }



    /**
     * 5.保证实现了Shiro内部lifecycle函数的bean执行
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 6.开启对shiro注解的支持
     *   AOP式方法级权限检查
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 7.配合DefaultAdvisorAutoProxyCreator实现使用注解进行权限校验,例如:@RequireRoles、@RequirePermissions等
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager());
        return authorizationAttributeSourceAdvisor;
    }




    //8.配置shiro的过滤器工厂再web程序中,shiro进行权限控制全部是通过一组过滤器集合进行控制
    @Bean
    public ShiroFilterFactoryBean shiroFilter() {
        //1.创建过滤器工厂
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        //2.设置安全管理器
        filterFactory.setSecurityManager(defaultWebSecurityManager());
        //3.通用配置(跳转登录页面,为授权跳转的页面)
        filterFactory.setLoginUrl("/autherror");//跳转url地址
        //4.设置过滤器集合
        //key = 拦截的url地址
        //value = 过滤器类型
        Map<String,String> filterMap = new LinkedHashMap<>();
        //key:请求规则   value:过滤器名称
        filterMap.put("/login","anon");//当前请求地址可以匿名访问
        filterMap.put("/user/**","authc");//当前请求地址必须认证之后可以访问
        //在过滤器工程内设置系统过滤器
        filterFactory.setFilterChainDefinitionMap(filterMap);

        return filterFactory;
    }

}

至此,准备阶段就结束了,可以进行shiro框架功能的测试。

step2:认证功能

认证流程在前文已经叙述过,这里不再赘述,下文主要描述怎么利用shiro实现认证。首先用户在登录界面输入用户名和密码,因为我们在数据库里存的是密文,所以需要先判断该用户名和密码,这个时候,根据我们在配置类中自定义的Realm类中的doGetAuthenticationInfo方法进行认证

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
//将参数AuthenticationToken 转换为用户名密码令牌
        UsernamePasswordToken token=(UsernamePasswordToken)authenticationToken;
//获取令牌中的用户名
        String username = token.getUsername();
//按照该用户名查询数据库,若数据库中没有数据,说明该用户不存在,返回null,若存在,进行验证
        User user = userService.findUserByName(username);
        if(user!=null){
//SimpleAuthenticationInfo:该类是shiro提供的对象,可以根据传入的参数进行解密操作
/**参数含义
*参数1:安全对象,后续用于鉴权
*参数2:从数据库中查到的密文密码
*参数3:从数据库中查到的盐值的字节数组
*参数4:realm类名
*/
            SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), ByteSource.Util.bytes(user.getSalt()), "myRealm");
            return info;
        }
        return null;
    }

这个时候就有人有问题了,这个参数authenticationToken里面的数据是怎么来传过来的?🆗,解释一下,在我们访问登录页面输入数据时,在控制层中,会先进行判断,若不为空,将数据封装成UsernamePasswordToken对象,再获取Subject对象,调用login方法进行登录验证,否则处理空异常。

 这个时候,又有人会有问题了,之前设置了加密算法和加密次数,那shiro框架在解密的时候怎么知道你用的是哪个加密算法,加密了多少次啊?🆗再解释一下,在Realm类中其实还有一个方法initCredentialsMatcher(),它是用来指导密码的加密算法和迭代次数的,写完后告诉shiro你的这个实现类是谁,shiro就知道该去回调哪个方法了。

step3:授权鉴权

这个功能主要是用户在访问某个功能鉴权的的时候使用,也就说,每当我访问一个新的功能进行鉴权的时候,都需要重新执行授权方法,该方法同样定义在Realm类中

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
//获取认证通过的用户对象
        User user =  (User) principalCollection.getPrimaryPrincipal();
//根据用户id查询该用户的详细信息
        User userDetail = userService.findUserDetailById(user.getId());
//定义存储角色的集合
        HashSet<String> roles = new HashSet<>();
//定义存储权限的集合
        HashSet<String> perms = new HashSet<>();
//对角色集合进行遍历,将每一个角色对应的的权限存入权限集合
        for (Role role : userDetail.getRoles()) {
            for (Permission perm : role.getPermissions()) {
                perms.add(perm.getCode());
            }
        }
//封装角色权限对象返回
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setStringPermissions(perms);
        info.setRoles(roles);
        return info;
    }

 对于后续的鉴权,我使用注解解决

        在资源上使用@RequiresPermissions注解,那么当用户访问该资源时判断用户有没有相应的权限 ,若有,可以访问资源,若无,抛出异常。对于异常情况的处理,使用全局异常处理器@ControllerAdvice进行捕获

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arcgis colorRmap

arcgis中colorRmap对应的名称&#xff1a; 信息来源&#xff1a;https://developers.arcgis.com/documentation/common-data-types/raster-function-objects.htm 在arcpy中使用方法&#xff1a; import arcpy cr arcpy.mp.ColorRamp("Yellow to Red")python中 ma…

基于安卓的考研助手系统app 微信小程序

&#xff0c;设计并开发实用、方便的应用程序具有重要的意义和良好的市场前景。HBuilder技术作为当前最流行的操作平台&#xff0c;自然也存在着大量的应用服务需求。 本课题研究的是基于HBuilder技术平台的安卓的考研助手APP&#xff0c;开发这款安卓的考研助手APP主要是为了…

下一代存储解决方案:湖仓一体

文章首发地址 湖仓一体是将数据湖和数据仓库相结合的一种数据架构&#xff0c;它可以同时满足大数据存储和传统数据仓库的需求。具体来说&#xff0c;湖仓一体可以实现以下几个方面的功能&#xff1a; 数据集成&#xff1a; 湖仓一体可以集成多个数据源&#xff0c;包括结构…

TCP学习笔记

最近面试&#xff0c;问TCP被问住了&#xff0c;感觉背八股背了印象不深刻&#xff0c;还是总结一些比较好。 如果有写错的&#xff0c;欢迎批评指正。 参考&#xff1a;https://www.xiaolincoding.com/network/3_tcp/tcp_interview.html#tcp-%E5%9F%BA%E6%9C%AC%E8%AE%A4%E8…

qt在线包下载安装出错 无法检索远程树

我的问题好像是在安装Qt5.15.2出现的。 我的情况是由于网络问题问题&#xff0c;设置开启了本机的代理之后&#xff0c;就可以正常下载了。

Java小游戏

一、需求 二、思路一 HP当然是怪物的一个属性成员&#xff0c;而武器是角色的一个属性成员&#xff0c;类型可以使字符串&#xff0c;用于描述目前角色所装备的武器。角色类有一个攻击方法&#xff0c;以被攻击怪物为参数&#xff0c;当实施一次攻击时&#xff0c;攻击方法被调…

C++设计模式之适配器模式

一、适配器模式 适配器模式&#xff08;Adapter Pattern&#xff09;是一种结构型设计模式&#xff0c;用于将一个类的接口转换成另一个类所期望的接口&#xff0c;以便两个类能够协同工作。 适配器模式可以解决现有类接口与所需接口不匹配的问题&#xff0c;使得原本因接口不…

BlazorServer中C#与JavaScript的相互调用

BlazorServer中C#与JavaScript的相互调用 前言&#xff1a; ​ 虽然BlazorServer中推荐使用C#在razor页面中的替代JavaScript来完成逻辑的编写&#xff0c;但当需要使用第三方的javascript文件/组件里的内容时&#xff0c;则难免要在C#中调用其方法或对象。反之当你的(用到第…

湖北咸宁农业三维扫描数字化农业3d打印制造应用-CASAIM中科广电

农业是人类衣食之源、生存之本&#xff0c;是一切生产的首要条件&#xff0c;CASAIM在农业三维扫描和3d打印应用上有丰富经验。 1.三维扫描技术在农业领域的应用 CASAIM三维扫描是集光学、机电和计算机技术于一体的高新无损检测技术&#xff0c;能够对实物的空间外形、结构乃…

Redis数据结构全解析【万字详解】

文章目录 前言一、SDS1、SDS的必要性2、SDS的数据结构3、SDS的优势O&#xff08;1&#xff09;复杂度获取字符串长度二进制安全不会发生缓冲区溢出节省空间 二、链表1、结构设计2、优缺点 三、压缩列表1、结构设计2、连续更新3、压缩列表的缺陷 四、哈希表1、结构设计2、哈希冲…

ubuntu安装goland

下载并解压goland sudo tar -C /opt/ -xzvf goland-2023.1.3.tar.gz配置应用图标 新建文件&#xff1a; vim /usr/share/applications/goland.desktop文件中写入如下内容&#xff1a; [Desktop Entry] TypeApplication NameGoLand Icon/opt/GoLand/bin/goland.png Exec/op…

科技赋能,教育革新——大步迈向体育强国梦

在 "全民健身"、"体育强国建设"战略的推进下&#xff0c;体育考试成绩被纳入重要升学考试且分值不断提高&#xff0c;体育科目的地位逐步上升到前所未有的高度&#xff0c;在此趋势下&#xff0c;体育教学正演变出更多元化、个性化的需求。然而现实中却面临…

centos7安装MySQL8

Centos7安装MySQL8 MySQL版本&#xff1a;8.0.34 1.安装前准备 &#xff08;1&#xff09;查看是否安装mariadb [rootkb135 ~]# rpm -qa|grep mariadb &#xff08;2&#xff09;卸载mariadb并检查是否卸干净 [rootkb135 ~]# rpm -e --nodeps mariadb-libs-5.5.68-1.el7.x8…

【C语言】2023.8.27C语言入学考试复盘总结

前言 本篇文章记录的是对于2023年8月27日的 C语言 的入学考试的整理总结 成绩&#xff1a;220/240 题目&#xff1a;9/12 错题整理 首先先对于我没做出来的三道题做一个整理 错题1&#xff1a;7-4 分段函数PLUS 题干 以下是一个二元分段函数&#xff0c;请你根据所给的函…

SketchBook软件安装包分享(附安装教程)

目录 一、软件简介 二、软件下载 一、软件简介 SketchBook是一款由Autodesk公司开发的绘画和绘图软件&#xff0c;它适用于各种操作系统和平台&#xff0c;如Windows、macOS、iOS和Android等。 SketchBook是一款专业的绘图软件&#xff0c;旨在满足各种绘画和绘图需求。它提…

TensorBoard的使用

TensorBoard&#xff1a;对图像进行变换 1. SummaryWriter的使用 ctrl类出现注释解析&#xff1a; 将条目直接log_dir写入要成为由TensorBoard使用。 “摘要编写器”类提供了一个高级 API 来创建事件文件&#xff0c;并在给定目录中添加摘要和事件。该类更新文件内容异步。…

如何配置一个永久固定的公网TCP地址来SSH远程树莓派?

文章目录 如何配置一个永久固定的公网TCP地址来SSH远程树莓派&#xff1f;前置条件命令行使用举例&#xff1a;修改cpolar配置文件 1. Linux(centos8)安装redis数据库2. 配置redis数据库3. 内网穿透3.1 安装cpolar内网穿透3.2 创建隧道映射本地端口 4. 配置固定TCP端口地址4.1 …

【Apollo学习笔记】——规划模块TASK之PATH_REUSE_DECIDER

文章目录 前言PATH_REUSE_DECIDER功能简介PATH_REUSE_DECIDER相关配置PATH_REUSE_DECIDER总体流程PATH_REUSE_DECIDER相关子函数IsCollisionFreeTrimHistoryPathIsIgnoredBlockingObstacle和GetBlockingObstacleS Else参考 前言 在Apollo星火计划学习笔记——Apollo路径规划算…

【CSS】CSS 特性 ( CSS 优先级 | 优先级引入 | 选择器基本权重 )

一、CSS 优先级 1、优先级引入 定义 CSS 样式时 , 可能出现 多个 类型相同的 规则 定义在 同一个元素上 , 如果 CSS 选择器 相同 , 执行 CSS 层叠性 , 根据 就近原则 选择执行的样式 , 如 : 出现两个 div 标签选择器 , 都设置 color 文本颜色 ; <style>div {color: re…

Cookie for Mac:隐私保护工具保护您的在线隐私

随着互联网的发展&#xff0c;我们每天都会浏览各种网站&#xff0c;享受在线购物、社交娱乐和学习资料等各种便利。然而&#xff0c;您是否曾经遇到过需要频繁输入用户名和密码的情况&#xff1f;或者不方便访问您常用的网站&#xff1f;如果是这样&#xff0c;那么Cookie for…