Springboot整合Shiro进行权限认证-两种获取realm的方式

阅读本博客预计消耗你20分钟的时间,看完此博客希望对你掌握Shiro框架有一定帮助

在学习之前我们先了解了解shiro,防止掉坑,减少一些不必要的误知,内容稍多,如果有使用经验,建议选择性阅读,没有建议从博客开始阅读,阅读本博客大约 5-15分钟。

1. 什么是Shiro?

1.1 Shiro的官网解释

Apache Shiro™是一个功能强大且易于使用的Java安全框架,它执行身份验证,授权,加密和会话管理。使用Shiro易于理解的API,您可以快速轻松地保护任何应用程序-从最小的移动应用程序到最大的Web和企业应用程序

特点:属于Apache开源组织的一个产品,功能强大并且易用的Java安全框架

  • 可以完成用户认证、授权、密码以及会话管理
  • 可以在任何的应用系统中使用(主要针对单体项目的权限管理)
  • 易于使用
  • 具有Web功能,允许基于应用程序URL和Web协议(例如REST)创建灵活的安全策略,同时还提供一组JSP库来控制页面输出
  • Shiro干净的API和设计模式使它易于与许多其他框架和应用程序集成。
  • 支持,Spring,Grails,Wicket,Tapestry,Tynamo,Mule和Vaadin
1.2 Shiro的核心

Shiro提供了应用程序安全性API来执行以下方面(应用程序安全性的4个基石):

  • 身份验证-证明用户身份,通常称为用户“登录”。

  • 授权-访问控制

  • 密码术-保护或隐藏数据以防窥视

  • 会话管理-每个用户的时间敏感状态

2. Shiro的工作原理

2.1 Shiro的四大核心功能
  • Authentication 认证验证用户是否有相应的身份—登录认证

  • Authorization 授权,即权限认证:对已经通过认真的用户检查是否具有某个权限或者角色,从而控制是否能进行某种操作

  • Session Manager 会话管理,用户在认证成功之后创建会话,在没有退出之前,当前用户的所有信息都会保存在这个会话中,可以是普通的JavaSE应用,也可以是web应用

  • Cryptography 加密 对敏感信息进行加密处理,shiro就提供了这种加密的机制

  • 支持的特性:

    • Web Support --shiro提供了过滤器,可以通过过滤器拦截web请求来处理web应用的访问控制
    • Caching 缓存支持 shiro可以缓存用户信息以及用户的角色权限信息,可以提高执行效率
    • Concurrency shiro支持多线程应用
    • Testing 提供测试支持
    • Run As 允许一个用户以另一种身份去访问
    • Remeber Me
    • 说明:Shiro是一个安全框架,不提供用户、权限的维护(用户的权限管理需要我们自己去设计)
2.2 Shiro的核心组件

原理图:
原理图

  • Shiro的三大核心组件(Subject、Security Manager、Realms)

    • Shiro工作流程示意图:
      工作流程图

    • Subject 表示待认证授权的用户

    • Security Manager,它是Shiro框架的核心,Shiro就是通过Security Manager 来进行内部实例的管理,并通过它来提供给安全管理的各种服务。

      • Authenticator 认证器
      • Ahthorizer 授权器
      • SessionManager 会话管理器
      • CacheManager 缓存管理器
    • Realm 相当于Shiro进行认证和授权的数据源,充当了Shiro与安全数据之间的桥梁或者连接器,也就说说对用户信息进行认证(登录)和授权(访问控制)验证时,Shiro会用应用配制的Realm中查找用户及其权限信息。

3. Shiro知识点详情概要

3.1 什么是权限管理?

不同身份的用户进入到系统所能完成的操作是不相同的,我们对不同用户的可执行的操作的管理称之为用户的权限管理。

3.2 如何实现权限管理

权限管理设计

  • 基于主页的权限管理(不同用户使用不同的主页,权限通过主页功能菜单限制)

  • 适用于权限管理比较单一、用户少、每类权限固定

  • 基于用户和权限的权限管理

  • 可以实现权限的动态分配,但是不够灵活

  • RBAC 基于角色的访问控制 (Role-Based Access Control )

    • 表格 (用户表(所有员工)、角色表(所有职位)、用户角色表(员工的职位)、

      系统权限表(权限资源)、角色权限表(统一授权)、用户权限表(单独授权))

3.3 认证授权
  • 认证:对用户的身份进行检查(登录验证)

  • 授权:对用户的权限进行检查(是否有对应的操作权限)

3.4 安全框架
  • 帮助我们完成用户身份认证及身份检查功能框架
  • 常用的安全框架:
    • Shiro:Apache Shiro是一个功能强大且易用的Java安全框架(小而简单)
    • Spring Security :基于Spring的一个安全框架,依赖于Spring
    • OAuth2:第三方的授权登录
    • 自定义安全认证中心

4. 如何使用Shiro

4.1 基于JavaSE的基本使用
4.1.1 创建Maven工程

不需要导入任何骨架,直接创建一个简单的Maven工程即可

4.1.2 导入Shiro的依赖库
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.4.1</version>
</dependency>
4.1.3 创建Shiro配置文件
  • 在resource目录下创建名为shiro.ini的文件

  • 在shiro.ini文件中完成用户、角色及权限的配置

    [users]
    zhangsan=123456,seller
    lisi=666666,ckmgr
    admin=222222,admin
    
    [roles]
    admin=*
    seller=order-add,order-del,order-list
    ckmgr=ck-add,ck-del,ck-list
    
  • 实现代码:

    Scanner sc =  new Scanner(System.in);
    System.out.println("请输入账号:");
    String username = sc.next();
    System.out.println("请输入密码:");
    String password = sc.next();
    // 拿到一个安全管理器对象
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    // 创建一个安全数据源
    IniRealm IniRealm = new IniRealm("classpath:shiro.ini");
    // 将安全数据源交给安全管理器
    securityManager.setRealm(IniRealm);
    // 将Realm设置给SecurityUtils工具
    SecurityUtils.setSecurityManager(securityManager);
    // 通过SecurityUtils工具类获取Subject对象
    Subject Subject = SecurityUtils.getSubject();
    // 【认证流程】
    // 将认证账号和密码封装到token对象中
    UsernamePasswordToken token = 
    new UsernamePasswordToken(username,password);
    // 接收验证结果
    boolean result = false;
    try {
        // 将令牌交给Subject
        Subject.login(token);
        result = true;
        }catch (IncorrectCredentialsException e){
        result = false;
    }
    System.out.println(result?"登录成功":"登录失败");
    // 【授权】
    // 判断登录的用户是否是特定角色
    System.out.println("是不是销售员: "+Subject.hasRole("seller"));
    // 判断登录的用户是否具有特定权限
    System.out.println("是否具有订单的删除功能: "+
    Subject.isPermitted("order-del"));
    
4.2 SpringBoot-整合Shiro(ini文件方式)
4.2.1 导入shiro依赖
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>1.4.1</version>
</dependency>
4.2.2 导入thymeleaf相关依赖
<!-- 修改thymeleaf版本 -->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
		
<!-- 修改thymeleaf版本 -->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.0.RELEASE</spring-boot.version>

<!-- 导入thymeleaf依赖-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
  • Shiro配置 (Java配置方式)

    • SpringBoot默认没有提供shiro的自动配置

      @Configuration
      public class ShiroConfig {
      	@Bean
      	public IniRealm getIniRealm() {
      		// 返回一个安全数据源 从文件中读取
      		IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
      		return iniRealm;
      	}
      	@Bean
      	public DefaultWebSecurityManager getDefaultWebSecurityManager
              (IniRealm iniRealm) {
      		// 将数据源交给Web默认安全管理器
      		DefaultWebSecurityManager securityManager = 
                  new DefaultWebSecurityManager();
      		securityManager.setRealm(iniRealm);
      		return securityManager;
      	}
      	@Bean
      	public ShiroFilterFactoryBean shiroFilterFactoryBean
              (DefaultWebSecurityManager securityManager) {
      		// 过滤器
      		ShiroFilterFactoryBean filter = new ShiroFilterFactoryBean();
      		// 过滤器就是shiro进行权限校验的核心,认证权限校验需要securityManager
      		filter.setSecurityManager(securityManager);
      		
      		// 设置Shiro的拦截规则
      		/**
      		 * anon 匿名用户可访问
      		 * authc 认证用户可访问
      		 * user 使用RemeberMe的用户可访问
      		 * perms 对应权限可访问
      		 * role 对应的角色可访问
      		 */
      		Map<String, String> filterMap = new HashMap<String,String>();
      		filterMap.put("/", "anon");
      		filterMap.put("/login.html", "anon");
      		filterMap.put("/regist.html", "anon");
      		filterMap.put("/user/login", "anon");
      		filterMap.put("/user/regist", "anon");
      		filterMap.put("/static/**", "anon");
      		filterMap.put("/**", "authc");
      		// 将规则发布给过滤器
      		filter.setFilterChainDefinitionMap(filterMap);
      		
      		// 设置默认的登录界面
      		filter.setLoginUrl("/login.html");
      		// 设置未授权访问的界面路径
      		filter.setUnauthorizedUrl("/login.html");
      		return filter;
      	}
      }
      
  • 认证测试

    • UserServiceImpl

      // 将账号密码交给令牌 
          public void checkLogin(String username,String password) throws Exception{
              Subject subject = SecurityUtils.getSubject();
              UsernamePasswordToken token = new UsernamePasswordToken
              (username, password);
              subject.login(token);
          }
      
    • UserController

      @Controller
      @RequestMapping("user")
      public class UserController {
      	@Resource
      	private UserServiceImpl userService;
      	
      	@GetMapping("/login")
      	public String login(String username,String password) {
      		try {
      			userService.checkLogin(username, password);
      			System.out.println("登录成功");
      			return "index";
      		} catch (Exception e) {
      			System.out.println("登录失败");
      			return "login";
      		}
      	}
      
      }
      
    • PageController

      @GetMapping("/login.html")
      	public String login() {
      		return "login";
      	}
      	
      	@RequestMapping("/")
      	public String login1() {
      		return "login";
      	}
      
      	@GetMapping("/index.html") 
      	public String index() {
      		return "index";
      	}
      
4.3 SpringBoot-整合Shiro -jdbc

使用shiro内置JDBC需要对表格关系进行设计,才可使用

创建SpringBoot工程时,导入Mybatis、thymeleaf、SpringBootDevTools、SpringWeb

#####导入Shiro的spring依赖,配置yml文件

  • 表名

    users(用户表)、user_roles(用户角色表)、roles_permissions(角色权限表)

  • 用户表字段

    id(用户ID)、username(用户名)、password(用户密码)、password_salt(加盐)

  • 用户角色表字段

    id(用户角色表ID)、username(用户名)、role_name(角色名)

  • 角色权限表

    id(角色权限ID)、role_name(角色名)、permission(权限标识)

  • 配置jdbcRealm

    @Bean
    	public JdbcRealm getJdbcRealm(DataSource dataSource) {
    		JdbcRealm realm = new JdbcRealm();
    		// jdbcReaml会自行从数据库查询用户及权限数据(数据库的表结构要符合jdbcRealm的规格)
    		realm.setDataSource(dataSource);
    		// 默认只开启认证功能,手动开启权限功能
    		realm.setPermissionsLookupEnabled(true);
    		return realm;
    	}
    

    使用jdbc的时候,我们获取realm的来源就不再是ini文件,而是数据库,ShiroDialect方法(下面有)也得加上,减少报错的机率,其余控制器,业务还有配置的代码都是一样的,面对CtrlCV编程就可以了

— 创建改变语法的方法

@Bean(name = "getShiroDialect")
public ShiroDialect getShiroDialect() {
	return new ShiroDialect();
}
4.4 Shiro的标签使用

​ Shiro提供了一套标签用于在页面来进行权限数据的呈现

  1. ​ 导入依赖
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
<!--可能需要改变thymeleaf的版本配置 -->
<thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
<thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>        
  1. 模板引擎
<html lang="zh_CN" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
  1. 使用Shiro标签来获取显示角色的权限和用户的认证
<!-- 游客显示的内容 -->
        <shiro:guest>
        	欢迎游客访问,<a href="login.html">登录</a>
        </shiro:guest>
        <!-- 登录的用户显示的内容 -->
        <shiro:user>
        	恭喜用户[<shiro:principal/>]登录成功<br/>
        	当前用户为<shiro:hasRole name="admin">超级管理员</shiro:hasRole>
        	<shiro:hasRole name="cmanager">仓管人员</shiro:hasRole>
        	<shiro:hasRole name="xmanager">销售人员</shiro:hasRole>
        	<shiro:hasRole name="kmanager">客服人员</shiro:hasRole>
        	<shiro:hasRole name="zmanager">行政人员</shiro:hasRole>
        </shiro:user>
        <h3>仓库管理</h3>
        <ul>
        	<shiro:hasPermission name="sys:c:save">
        	<li><a href="#">入库</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:c:delete">
        	<li><a href="#">出库</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:c:update">
        	<li><a href="#">更库</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:c:find">
        	<li><a href="#">查库</a></li>
        	</shiro:hasPermission>
        </ul>
         <h3>订单管理</h3>
        <ul>
        	<shiro:hasPermission name="sys:x:save">
        	<li><a href="#">添加订单</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:x:delete">
        	<li><a href="#">删除订单</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:x:update">
        	<li><a href="#">修改订单</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:x:find">
        	<li><a href="#">查询订单</a></li>
        	</shiro:hasPermission>
        </ul>
         <h3>客户管理</h3>
        <ul>
        	<shiro:hasPermission name="sys:k:save">
        	<li><a href="#">添加客户</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:k:delete">
        	<li><a href="#">删除客户</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:k:update">
        	<li><a href="#">修改订单</a></li>
        	</shiro:hasPermission>
        	<shiro:hasPermission name="sys:k:find">
        	<li><a href="#">查询订单</a></li>
        	</shiro:hasPermission>
        </ul>
注意事项:
  • 因为我们使用的是thymeleaf的模板引擎,所以要使用动态文件夹template下,如果你的页面有外部文件,就使用thymeleaf 表达式【th:src=“@{js/vue.js}”】导入外部文件
  • 登录界面
	<div style="margin:0px auto;height:100px;width:100px;">
	<form action="/user/login">
		<input name="username"  type="text"  placeholder="请输入用户名..."  /><br/>
		<input name="password"   type="password"  placeholder="请输入密码...." /><br/>
		<input type="submit" value="登录" />
	</form>
</div>
  • 主页面 (别忘记在xmlns中导入模板引擎,上面有)
<body>
   <div id="dv">
   <!-- 游客显示的内容 -->
       <shiro:guest>
       	欢迎游客访问,<a href="login.html">登录</a>
       </shiro:guest>
       <!-- 登录的用户显示的内容 -->
       <shiro:user>
       	恭喜用户[<shiro:principal/>]登录成功<br/>
       	当前用户为<shiro:hasRole name="admin">超级管理员</shiro:hasRole>
       	<shiro:hasRole name="cmanager">仓管人员</shiro:hasRole>
       	<shiro:hasRole name="xmanager">销售人员</shiro:hasRole>
       	<shiro:hasRole name="kmanager">客服人员</shiro:hasRole>
       	<shiro:hasRole name="zmanager">行政人员</shiro:hasRole>
       </shiro:user>
       <h3>仓库管理</h3>
       <ul>
       	<shiro:hasPermission name="sys:c:save"><li><a href="#">入库</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:c:delete"><li><a href="#">出库</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:c:update"><li><a href="#">更库</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:c:find"><li><a href="#">查库</a></li></shiro:hasPermission>
       </ul>
        <h3>订单管理</h3>
       <ul>
       	<shiro:hasPermission name="sys:x:save"><li><a href="#">添加订单</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:x:delete"><li><a href="#">删除订单</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:x:update"><li><a href="#">修改订单</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:x:find"><li><a href="#">查询订单</a></li></shiro:hasPermission>
       </ul>
        <h3>客户管理</h3>
       <ul>
       	<shiro:hasPermission name="sys:k:save"><li><a href="#">添加客户</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:k:delete"><li><a href="#">删除客户</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:k:update"><li><a href="#">修改订单</a></li></shiro:hasPermission>
       	<shiro:hasPermission name="sys:k:find"><li><a href="#">查询订单</a></li></shiro:hasPermission>
       </ul>
   </div>
</body>
  • yml/propertties文件配置数据库的数据源 (不配置数据源mybatis会提示错误)
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/test?serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
// 日志详细信息
logging.level.web=debug
spring.mvc.log-request-details=true
  • 最后给大家看一下我的工程结构,这篇菜鸟博客就写完了
    在这里插入图片描述
    有问题欢迎在博客下留言,希望能帮助到你,再会
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
web.xml配置 因为我们是与spring进行集成的,而spring的基本就是web项目的xml文件。所以我们在web.xml中配置shiros的过滤拦截。正常情况下,我们需要将shiro的filter配置在所有的filter前面,当然和encodingFilter这个filter是不区分前后的。因为两者互相不影响的。spring-shiro.xml 这里我们将来看看spring-shiro.xml的配置,这里我采取倒叙的方式讲解,我觉的倒叙更加的有助于我们理解代码。首先我们还记得在web.xml中配置的那个filter吧,名字shiroFilter,对spring-shiro.xml配置文件就是通过这个filter展开的。首先我们在web.xml配置的过滤器实际上是配置ShiroFilterFactoryBean,所以在这里需要将ShiroFilterFactoryBean定义为shiroFilter <!-- Shiro的核心安全接口,这个属性是必须的 --> <!-- 要求登录时的链接(可根据项目的URL进行替换),非必须的属性,默认会自动寻找Web工程根目录下的"/login.html"页面 --> <!-- 登录成功后要跳转的连接 --> <!-- 用户访问未对其授权的资源时,所显示的连接 --> <!-- 若想更明显的测试此属性可以修改它的值,如unauthor.jsp,然后用[玄玉]登录后访问/admin/listUser.jsp就看见浏览器会显示unauthor.jsp --> <!-- Shiro连接约束配置,即过滤链的定义 --> <!-- 此处可配合我的这篇文章来理解各个过滤连的作用http://blog.csdn.net/jadyer/article/details/12172839 --> <!-- 下面value值的第一个'/'代表的路径是相对于HttpServletRequest.getContextPath()的值来的 --> <!-- anon:它对应的过滤器里面是空的,什么都没做,这里.do和.jsp后面的*表示参数,比方说login.jsp?main这种 --> <!-- authc:该过滤器下的页面必须验证后才能访问,它是Shiro内置的一个拦截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter --> /statics/**=anon /login.html=anon /sys/schedule.html=perms[sys:schedule:save] /sys/login=anon /captcha.jpg=anon /**=authc
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

心系编程

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值