Apache Shiro是一个Java的安全(权限)框架.
Shiro可以非常容易的开发出足够好的应用,其不仅可以用在JavaSe环境,也可以用在JavaEE环境
Shiro可以完成,认证,授权,加密,会话管理,Web集成
官网:https://shiro.apache.org
里面有Shiro 在gitee的下载地址什么的,看不懂,1分钟就解决了
建议好好读一下:
三个核心组件:Subject, SecurityManager 和 Realms.
Subject:即“当前操作用户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。
Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。
SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。
Realm: Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。
从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。
Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果系统默认的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。
记住:
Subject subject=SecurityUtils.getSubject();
得到subject对象
UsernamePasswordToken token=new UsernamePasswordToken(username,password);
为什么需要这个token对象的原因。因为login方法需要该对象
subject.login(token)
好了这样用户信息就提交给SecurityManager了
---------------------------------------------------------------------------------------------------------------------------------
这些都是核心代码.稍微有个印象
上面的是简写,详细点如下:
//准备提交给SecurityManager的对象,我们需要设置值交给SecurityManager
Subject curentUser=SecurityUtils.getSubject()
//通过当前用户拿到Session
Session session=curentUser.getSession();
session.setAttribute("someKey","aValue");
String value=(String)session.getAttribute("someKey");
if(value.equals("aValue")){
log.info("登录成功")
}
//如果是没有认证的用户:
if(!curentUser.isAuthenticated()){
UsernamePasswordToken token=new UsernamePasswordToken("admin","123456");
token.setRememberMe(true);//设置记住我
try{
curentUser.login(token);//这个其实就是将用户信息提交给SecurityManager
}catch(UnknowAccountException e){//未知的账户
log.info("There is no user with username of"+token.getPrincipal());
}catch(IncorrectCredentialsException e){//用户锁定比如5次密码不对
log.info("Password for account "+token.getPrincipal()+"was incorrect");
}catch(LockedAccountException e){
log.info("xxxxxx");
}catch(AuthenticationException e){//认证异常 上面都是子类异常
log.info(",........")
}
}
比如当前用户是什么角色
if(currentUser.hasRole("yyyy")){
xxxxx
}else{
log.info("xxxx");
}
用户有什么权限
if(currentUser.isPermitted("xxxx")){
xxxxxxxxxx
}
登出
currentUser.logout()
以上代码,都先混个眼熟.
下面正式开始SpringBoot集成Shiro
原先也写过:SpringBoot项目整合Shiro_fhrui的博客-CSDN博客_springboot项目整合shiro
当复习了.
其实Shiro文档里都有,学会看文档,但是我不会
开始创建项目
引入Spirng web
还有Thymeleaf模板
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.0</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.hrui</groupId>
<artifactId>springboot-shiro</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-shiro</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Shiro依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>-->
<artifactId>shiro-spring-boot-web-starter</artifactId>-->
<version> 1.7.1</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
上面的shiro依赖先注释一下,先测试下Thymeleaf好不好用
写个控制器测试Thymeleaf
整个首页
启动项目
访问下
localhost:8080
Thymeleaf测试成功
现在导入Shiro依赖,把刚才注释掉的Shiro拿来用
启动报错
首先,需要自定义一个Realm
写个配置类,放在启动类里也可以
写点测试环境需要的东西
控制器加两接口
加两个页面
首页加两个跳转
启动测试下
访问
环境搭建好了
也都可以跳转
接下来要做的就是让有些页面可以跳转,有些有条件跳转
关于Shiro自定好的过滤连名称见官网
那如果我改成这样
那就是首页可以进,add和update 需要有认证才可以
试一下 localhost:8080
访问首页可以
点击进入add或者update 不让访问 重定向到了login.jsp ,但我们没写所以找不到
那么写一个再添加登录接口 配置里配置下
测试
localhost:8080 点击add或者update
改用通配符也可以
那么拦截是写好了
接下来做认证,就是用户账密传进来
写个登录接口
修改下登录页面将传过去的msg接收下
启动服务器
访问localhost:8080/login 点击提交
看后台输出
说明已经提交到认证方法,只不过我们在认证里啥也没做,返回了null
接下来,就去认证里干点好玩的事
重启下服务,访问
localhost:8080/login 输入amamaw 123456 点击提交
如果用户名错误,或者密码错误都会有相应报错其实,输入正确用户名和密码可以登录index.html
接着我们访问数据源,这里用Druid数据源 引入Druid(德鲁伊底层用的还是JDBC) Mybatis mysql驱动 log4j lombok Druid配置没整好
<dependency> <groupId>org.springframework.boot</groupId> 注意这里没有data不检查数据库 <artifactId>spring-boot-starter-data-jdbc</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.2.2</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <scope>runtime</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency>
创建application.yml配置数据源,算了Druid的配置太麻烦
spring:
datasource:
url: jdbc:mysql://localhost:3306/jt?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&autoReconnect=true&allowMultiQueries=true
username: root
password: 123456
#mybatis配置
mybatis:
type-aliases-package: com.hrui.pojo
mapper-locations: classpath:/mapper/*.xml
创建pojo
持久层
然后.xml配置文件
xml配置可以其他项目复制 或者mybatis官网入门_MyBatis中文网
业务层
数据库建表
插入点数据
测试下
那么现在可以在认证的方法中将数据变成从数据库查询出来的数据
测试下
访问 localhost:8080
点击add 或者update 被拦截 跳到登录页面
输入正确账密 允许登录且可以访问add update
下面讲下Shiro关于密码加密的问题
如果在用户注册时候,使用了加密方式比如说MD5
那么需要我们重写一个方法,Shiro会自动调用,
就是告诉Shiro我们是怎么对密码明文进行加密的
比如我将数据库密码改一下
该密码就是通过MD5 加密一次后生产的
然后重写Shiro要掉用的加密方法 比如你是MD5 或者MD5加盐值 如果有盐值,在认证返回时调用4个参数的构造 或者其他加密方式
重新访问 localhost:8080 访问登录 root 123456 访问也是OK的
认证基本差不多了,现在讲下授权
首先需要配置授权
访问
localhost:8080
随便几点add 或者update 到登录页
访问update是OK的
但是访问add报错401 Unauthorized 就是未授权
正常情况未授权会跳转到未授权页面,这里也写一下
控制器
配置类里指定未授权路径
重新访问
登录访问 add页面
看下后台
也就是说什么值权限,Shiro访问了授权方法,只不过授权里我们什么没写返回的是null
既然设置了权限,现在需要将权限赋值给用户
那么进入授权的方法
但是这样写的话,也就是说有登录用户都有该权限
这样访问就ok了,但是存在的问题是所有用户都有了该权限
其实在认证方法return时候返回的第一个参数,已经可以通过授权方法参数得到
就是单一用户的传递
这里在pojo User里加个权限字段 perms
数据库表里字段也加上
也就是说数据库该用户需要有具体的权限
当然 ,实际上角色权限实际和用户表是分开关联的
将update权限也加上
这样登录对应用户账号,只能访问可以访问的页面,没有权限就会跳转到没有权限页面
而现在更合理的需求解决是:只允许看到登录用户有权限看到的页面,
没有权限就不让他看到(原来是都可以看到,只是点进去显示没有权限)
引入Shiro整合Thymeleaf依赖
<!--Shiro整合Thymeleaf--> <dependency> <groupId>com.github.theborakompanioni</groupId> <artifactId>thymeleaf-extras-shiro</artifactId> <version>2.1.0</version> </dependency>
引入之后还需要配置
index.html修改下
这样其实访问 localhost:8080 add和update就都不显示了
我们先访问 localhost:8080/login 登录用户
登录root 只能看到 add
或者index.html加个登录按钮
其实上面有个问题,就是登录后 访问首页 权限还有 时因为Session没有清除
我在授权方法里放个Session进去
下面是我猜的,自己写个按钮试试,也不想验证了