工具类
j2113,day63
j2112,0304
Mybatis
参考:
day57-61视频
SpringBoot自动装配原理
参考:
SpringBoot整合Spring Data JPA
参考:
day72视频
1.创建springboot项目时,勾选Spring Data JPA 或者之后引入jpa依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
2.JPA配置---application.properties/yml
#配置数据库类型
spring.jpa.database=mysql
#配置生成数据库脚本策略
#update #每次运行程序,没有表格会新建表格,表内有数据不会清空,只会更新
#create #每次运行该程序,没有表格会新建表格,表内有数据会清空
#create-drop #----每次程序结束的时候会清空表
#validate #----运行程序会校验数据与数据库的字段类型是否相同,不同会报错
spring.jpa.hibernate.ddl-auto=update
#关于spring.jpa.hibernate.ddl-auto=update的解释
#jpa.hibernate.ddl-auto是hibernate的配置属性,其主要作用是:自动创建、更新、验证数据库表结构。该参数的几种配置如下:
#·create:每次加载hibernate时都会删除上一次的生成的表,然后根据你的model类再重新来生成新表,哪怕两次没有任何改变也要这样执行,这就是导致数据库表数据丢失的一个重要原因。
#·create-drop:每次加载hibernate时根据model类生成表,但是sessionFactory一关闭,表就自动删除。
#·update:最常用的属性,第一次加载hibernate时根据model类会自动建立起表的结构(前提是先建立好数据库),以后加载hibernate时根据model类自动更新表结构,即使表结构改变了但表中的行仍然存在不会删除以前的行。要注意的是当部署到服务器后,表结构是不会被马上建立起来的,是要等应用第一次运行起来后才会。
#·validate:每次加载hibernate时,验证创建数据库表结构,只会和数据库中的表进行比较,不会创建新表,但是会插入新值。
#显示执行的sql
spring.jpa.show-sql=true
3.在entity或者pojo中创建实体
@Entity(name="数据库表名")
public class User implements Serializable{
@Id /*声明此属性是数据库中主键*/
@Column(name="对应列名")
@GeneratedValue(strategy="") /*主键生成策略,AUTO,IDENTITY,SEQUENCE,TABLE*/
//可参考:https://www.cnblogs.com/xiaohouzai/p/8989378.html
private Integer id;
@Column(name="对应列名")
private String username;
@Column(name="对应列名")
private String password;
}
@Entity,@Table,使用的persistence包,不是hibernate
@Entity(name="数据库表名")
单独使用Entity,name属性里的数据库表名,需与当前类名相同,大小写字母忽略
或者
@Entity
@Table(name="数据库表名") 连用
4.在Repository中创建对应接口
@Repository //可写可不写
public interface UserRepository extends JpaRepository<实体名称,实体中主键数据类型>{
}
-
正常编写service
-
在service的实现层中,注入刚才的repository接口,它基本实现了简单的CRUD。
-
接着controller写代码即可
SpringDataJPA-分页
参考:
day73视频
-
创建XXXRepository接口,并继承JpaRepository
-
在serivce实现层或者是控制层中写代码
//设置分页
//org.springframework.data.domain.PageRequest;
//public static PageRequest of(int page, int size)
//page参数:从0开始,page-1便可以从第一页开始 ;size:每页显示的条数
PageRequest of = PageRequest.of(page-1, 2);
//查询所有的数据
// Page<T> findAll(Pageable var1); 使用JPARepository它的父接口的方法:将分页条件PageRequest带过来
//PageRequest 实现的接口Pageable
Page<Game> all = gameRepository.findAll(of);
//Page:获取到 总记录数以及分页的列表数据
System.out.println(all.getTotalElements()); //总记录数
System.out.println(all.getContent()); //分页列表数据
Springboot整合kaptcha验证码代码
参考:
day73视频
1.在pom.xml中,引入kaptcha的依赖
<dependency>
<groupId>com.github.penggle</groupId>
<artifactId>kaptcha</artifactId>
<version>2.3.2</version>
</dependency>
2.创建config包,并创建KaptchaConfig配置类
package com.j2113.config;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import com.google.code.kaptcha.util.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Properties;
/**
* @Project_Name: springboot
* @Package_Name: com.j2113.config
* @ClassName: KapchaConfig
* @Project_Path: com.j2113.config.KapchaConfig
* @Author: YHaooo
* @CreateTime: 2022-04-11 19:46
* @Description: TODO 验证码配置文件
*/
@Configuration
public class KaptchaConfig {
//@Bean方法名作为当前spring中bean的表示符号
@Bean //方法名:是Bean的唯一表示
public DefaultKaptcha defaultKaptcha() {
//创建DefaultKaptcha验证码对象
DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
//创建属性集合列表
Properties properties = new Properties();
//设置参数
//是否设置边框
properties.setProperty("kaptcha.border", "no");
//设置产生验证码的个数
properties.setProperty("kaptcha.textproducer.char.length", "4");
//设置产生的随机字符
properties.setProperty("kaptcha.textproducer.char.string", "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789");
//设置颜色
properties.setProperty("kaptcha.background.clear.to","211,229,237") ;
//创建Config对象,将属性集合类对象进去
Config config = new Config(properties) ;
//将配置类的所有参数信息存储到验证码对象
defaultKaptcha.setConfig(config) ;
return defaultKaptcha;
}
}
3.创建KaptchaController
package com.j2113.controller;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.imageio.ImageIO;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
/**
* @Project_Name: springboot
* @Package_Name: com.j2113.controller
* @ClassName: KaptchaController
* @Project_Path: com.j2113.controller.KaptchaController
* @Author: YHaooo
* @CreateTime: 2022-04-11 19:54
* @Description: TODO
*/
@Controller
@RequestMapping("/kaptcha")
public class KaptchaController {
//注入
@Autowired
private DefaultKaptcha defaultKaptcha ;
@RequestMapping("/getCode")
public void getCode(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
//将DefaultKaptcha产生的验证码存储到内存操作流对象中ByteArrayOutputStream
byte[] captchaChallengeAsJpeg = null;
//创建内存操作流对象---属于字节流的一种 (临时数据)
ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
try {
//生产验证码字符串并保存到session中
String createText = defaultKaptcha.createText();
//存储在session中
httpServletRequest.getSession().setAttribute("kaptcha", createText);
HttpSession session = httpServletRequest.getSession();
//使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中
BufferedImage challenge = defaultKaptcha.createImage(createText);
ImageIO.write(challenge, "jpg", jpegOutputStream);
}catch (Exception e) {
try {
httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
} catch (IOException ex) {
ex.printStackTrace();
}
return;
}
//定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组
captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
httpServletResponse.setHeader("Cache-Control", "no-store");
httpServletResponse.setHeader("Pragma", "no-cache");
httpServletResponse.setDateHeader("Expires", 0);
httpServletResponse.setContentType("image/jpeg");
ServletOutputStream responseOutputStream = null;
try {
responseOutputStream = httpServletResponse.getOutputStream();
responseOutputStream.write(captchaChallengeAsJpeg); responseOutputStream.flush();
responseOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
4.前端获取验证码请求路径
<div>
<input type="text" name="captcha" placeholder="请输入验证码" autocomplete="off" class="layui-input admin-input admin-input-verify">
<img id="kaptcha" class="admin-captcha" width="90" height="30" src="/kaptcha/getCode"> <!--src里为验证码的请求路径-->
</div>
5.刷新验证码js代码
<script>
$("#kaptcha").click(function () { //kaptcha对应img标签里设置的id
//时间戳
//为了使每次生成图片不一致,即不让浏览器读缓存,所以需要加上时间戳
var path = $(this).attr("src")+"?"+new Date().getTime();
$(this).attr("src",path);
//刷新方法2
// this.src="/kaptcha/getCode?"+new Date().getTime();
});
</script>
SpringBoot整合Swagger2
参考:
day71视频
1.引入依赖
<!--swagger的依赖包-->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.8.0</version>
</dependency>
2.创建Swagger2配置类
package com.qf.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
/**
* @author Kuke
* @date 2022/4/7 11:43
*
* swagger2工具
*/
@Configuration //标记这个类配置
//通过swagger2工具产生api接口文档(在线api文档/以及接口测试)
@EnableSwagger2
public class Swagger2Config {
@Bean //相当于之前使用.xml配置 bean标签 id="" class=""
public Docket api() { //生成文档:针对路径:com.qf.controller
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select() // 自行修改为自己的包路径
.apis(RequestHandlerSelectors.basePackage("项目中controller层的路径"))
.paths(PathSelectors.any())
.build(); }
//生成api解耦文档的方法
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("swagger-api文档")
.description("swagger接入教程") //服务条款网址
.version("1.0")
.build();
}
}
3.使用Swagger2
//访问的服务器端口/swagger-ui.html
端口为8080
localhost:8080/swagger-ui.html
SpringBoot整合Mail技术
参考:
day73视频
基础配置
-
在pom.xml中引入mail依赖
<!--导入mail启动器-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</artifactId>
</dependency>
-
在properties文件中,配置邮件参数
#配置smpt协议
spring.mail.host=smtp.qq.com
#邮件发送者,即这个邮箱给其他邮箱发送邮件
spring.mail.username=你的邮箱,由于这里配置的是QQ,所以使用QQ邮箱
#邮箱的授权码,可以在自己邮箱中获取
spring.mail.password=oluxfqflbzeybfdj
#配置发送邮件内容的编码格式,默认utf-8
spring.mail.default-encoding=utf-8
-
在需要邮件功能的地方,注入JavaMailSender
// 注入JavaMailSender
@Autowired
private JavaMailSender mailSender ;
基础使用
==邮件分三种发送模式:简单邮件,带有HTML样式邮件,带有附件邮件==
1.简单邮件
//1.简单邮件
@Value("${spring.mail.username}")
private String from ;
@Test
public void testSimpleMessage(){
//创建简单邮件消息对象
SimpleMailMessage simpleMailMessage = new SimpleMailMessage() ;
//设置它的一些参数
// private String from; 发送邮件者,自己的邮箱
simpleMailMessage.setFrom(from);
//private String to :邮件接收的用户
simpleMailMessage.setTo(接受者的邮箱);
// private String subject :设置主题,标题
simpleMailMessage.setSubject("测试邮件发送!");
// private String text :邮件的内容
simpleMailMessage.setText("这一封测试邮件,请查收!");
//开始发送
//JavaMailSender
//void send(SimpleMailMessage var1) throws MailException;
mailSender.send(simpleMailMessage) ;
}
2.带有HTML样式邮件
//2.带有HTML样式邮件
/**
* 方式2:发送一封邮件,针对邮件内容---通过html标签进行渲染,对内容进行 "高亮显示"
*/
@Value("${spring.mail.username}")
private String from ;
@Test
public void sendHtmlMail() throws MessagingException {
//1)创建MiMeMessage对象
//规定一些媒体格式
MimeMessage mimeMessage = mailSender.createMimeMessage();
//创建MimeMessageHelper对象
//public MimeMessageHelper(MimeMessage mimeMessage)
//参数2:表示可以发送的多个邮件 ,参数true,表示发送多封邮件
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true) ;
//发件者的邮箱,即自己的邮箱
mimeMessageHelper.setFrom(from) ;
//接收者
mimeMessageHelper.setTo("13335390494@163.com");
mimeMessageHelper.setSubject("这是一封带html格式的邮件");
//参数1:给标题
//参数2:true:表示可以解析的html标签
mimeMessageHelper.setText("这一个封测试邮件,邮件带有html格式的内容,<font color='red'>刘桑</font>",true);
//开始发送
mailSender.send(mimeMessage);
}
//参考代码:
public void testSendEmail(){
try {
JavaMailSender mailSender=new JavaMailSenderImpl();
mailSender.setHost("服务器名");
mailSender.setPort(3306);
mailSender.setUsername("用户名");
mailSender.setPassword("密码");
MimeMessage msg = mailSender.createMimeMessage();
// 设置utf-8或GBK编码,否则邮件会有乱码,true表示为multipart邮件
MimeMessageHelper helper = new MimeMessageHelper(msg, true, "utf-8");
// 邮件接收地址
helper.setTo("...@163.com");
// 设置抄送
helper.setBcc(new InternetAddress("...@163.com","接收人","utf-8"));
// 设置发送人邮件地址
helper.setFrom("sender@163.com","发送人");
//设置发送邮件的标题
helper.setSubject("发送邮件的标题");
// 设置邮件内容,注意加参数true,表示启用html格式
helper.setText("发送邮件的内容...", true);
//发送带有附件的可以省略...参数一:读取word文档,参数二:
helper.addAttachment(MimeUtility.encodeWord("Word文件名"),
new FileSystemResource(new File("文件地址")));
//第一个参数附件名,第二个参数附件
//发送邮件
mailSender.send(msg);
} catch (MailException e) {
e.printStackTrace();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
} catch (MessagingException e) {
e.printStackTrace();
}
}
3.带附件的邮件
/**
* 方式3:带附件带的邮件
*/
@Value("${spring.mail.username}")
private String from ;
@Test
public void sendFileMail() throws MessagingException {
//1)创建MiMeMessage对象
//规定一些媒体格式
MimeMessage mimeMessage = mailSender.createMimeMessage();
//创建MimeMessageHelper对象
//public MimeMessageHelper(MimeMessage mimeMessage)
//参数2:表示可以发送的多个邮件 ,参数true,表示发送多封邮件
MimeMessageHelper mimeMessageHelper = new MimeMessageHelper(mimeMessage,true) ;
//设置它里面的参数
mimeMessageHelper.setFrom(from) ;
//接收者
mimeMessageHelper.setTo("13335390494@163.com");
mimeMessageHelper.setSubject("这是一封带附件格式的邮件");
//内容
mimeMessageHelper.setText("这一封测试邮件,请查收!");
//创建对象:本地文件资源对象
//参数:指定本地文件地址
// public FileSystemResource(File file)
FileSystemResource fileSystemResource = new FileSystemResource(new File("d:\\高圆圆.jpg"));
//mimeMessageHelper,设置收件箱的附件的文件名称以及,将源文件读取过来
//参数1:文件名称
//参数2:数据源对象FileSystemResource
//public void addAttachment(String attachmentFilename, DataSource dataSource)
mimeMessageHelper.addAttachment("gaoyuanyuan.jpg",fileSystemResource) ;
//开始发送
mailSender.send(mimeMessage);
}
项目使用Mail技术,完成注册给邮箱发送验证码
在业务层完成编写
//注入JavaMailSender
@Autowired
private JavaMailSender mailSender ;
//properties中邮件的配置信息
@Value("${spring.mail.username}")
private String from ;
/**
* 邮件激活
* @param userName 用户名
* @param session session对象
* @return 自定义响应实体
*/
@Override
public BaseResp sendMail(Object userName, HttpSession session) {
//使用Springboot整合mail
//创建媒体消息对象(支持多邮件邮件发送或者单邮件发送)
MimeMessage mimeMessage = mailSender.createMimeMessage();
MimeMessageHelper mimeMessageHelper = null ;
//创建MimeMessageHelper这个对象,设置邮件参数
try {
mimeMessageHelper = new MimeMessageHelper(mimeMessage,true) ;
//设置参数
mimeMessageHelper.setFrom(from); //发送激活邮件的发送者
mimeMessageHelper.setTo(userName.toString()); //前端注册界面传过来的邮箱地址
mimeMessageHelper.setSubject("千锋教育平台邮件激活");
//产生随机生成的邮箱验证码
StringBuffer buffer = new StringBuffer() ;
for(int i = 0 ; i < 6 ; i++){
//Random:随机数生成器
int code = new Random().nextInt(10);
//将code追加字符串缓冲区中
buffer.append(code) ;
}
/* 针对上面使用random产生随机数,可使用下面的随机数工具类
<!--随机数工具类-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
String str = RandomStringUtils.randomAlphanumeric(6);
System.out.println("邮箱验证码:"+str);
*/
//等会发送之前,将用户名(邮箱)和产生的一个随机的邮箱激活码 对应的用户和激活码放进去
session.setAttribute(userName.toString(),buffer.toString());
//设置文本内容
mimeMessageHelper.setText("验证码为:<font color='red'>"+buffer.toString()+"</font>",true);
//开始发送邮件
mailSender.send(mimeMessage) ;
return new BaseResp(0,"发送邮件成功",null,null) ;
} catch (MessagingException e) {
e.printStackTrace();
}
return new BaseResp(1,"发送邮件失败",null,null) ;
}
SpringBoot整合七牛云文件上传
参考:
day66视频
day74视频
1.七牛云注册并开通云服务器
2.在pom.xml中引入七牛云依赖和其他所需依赖
//七牛云官方依赖
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>[7.7.0, 7.7.99]</version>
</dependency>
//其他依赖,还有其他需要可参考七牛云开发文档
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>3.14.2</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
<scope>compile</scope>
</dependency>
3.复制七牛云里,AK,SK,仓库名,外链,并配置到properties
#七牛云配置信息
qiniu.ak=你的AK
qiniu.sk=你的SK
qiniu.bucket=你的仓库名称
qiniu.url=http://ra84wb0fc.hd-bkt.clouddn.com/
#外链需补全http,并在后面加/,这是之后文件上传成功后生成的链接
4.创建工具类
==开发文档-文件上传-服务器直传-数据流上传,有参考代码==
package com.qf.utils;
import com.google.gson.Gson;
import com.qiniu.common.QiniuException;
import com.qiniu.http.Response;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.Region;
import com.qiniu.storage.UploadManager;
import com.qiniu.storage.model.DefaultPutRet;
import com.qiniu.util.Auth;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
/**
* @author Kuke
* @date 2022/3/26 14:15
* 使用七牛云通过 "数据流 上传图片"
*/
//类交给spring,创建对象
@Component
public class UploadUtils {
private UploadUtils(){}
//获取配置文件中的这些内容
@Value("${qiniu.ak}")
private String accessKey ;
@Value("${qiniu.sk}")
private String secretKey ;
@Value("${qiniu.bucket}")
private String bucket ;
@Value("${qiniu.url}")
private String url ;
/*
* 上传 方法 将本地磁盘上的图片存储七牛云(服务器)
*
* 返回:使用生成的域名+唯一的图片的名称
* */
public String uploadFile(MultipartFile multipartFile){ //使用数据流 ---将图片上传
//使用七牛云---sdk完成 上传 ---查看七牛云开发文档
//数据流的上传的代码--(七牛云的)
//构造一个带指定 Region 对象的配置类
Configuration cfg = new Configuration(Region.region0()); //huadong() //华东区域 (云存储的区域地址(服务器))
//...其他参数参考类注释
//上传管理器,将Configuration进行解析
UploadManager uploadManager = new UploadManager(cfg);
//...生成上传凭证,然后准备上传
//访问到七牛云的密钥(个人中心自己的)
// String accessKey = "yGotxUejuad1rVeY4Cc7kkgZ5HTQwSU1Yqdc90II"; //访问密钥
//String secretKey = "kofIM0oF8UtBkN398ZUEmOymJh9up3-9bi-EtO6F";//安全密钥
//等会需要将本地图片上传到七牛云指定个存储空间,七牛云的存储空间名称
// String bucket = "javaee-2113-upload";
//默认不指定key的情况下,以文件内容的hash值作为文件名
String key = null;
try {
//身份认证:将上面的配置好的访问密钥,和安全密钥封装到Auth
Auth auth = Auth.create(accessKey, secretKey);
//生成upToke="令牌字符串" 里面有空间名称以及accessKey, secretKey都在里面
String upToken = auth.uploadToken(bucket); //使用认证将指定的图片存储空间名称上
//使用uploadManager上传管理器上传
// public Response put(InputStream stream, String key, String token, StringMap params, String mime)
//参数1:上传文件的字节流
//参数2:哈希字符串
//参数3:upToken 密钥+空间名称 字符串
//参数4:其他参数
//参数5:文件类型
Response response = null;
response = uploadManager.put(multipartFile.getInputStream(),key,upToken,null, null);
//解析上传成功的结果
DefaultPutRet putRet = new Gson().fromJson(response.bodyString(), DefaultPutRet.class);
System.out.println(putRet.key);
System.out.println(putRet.hash);//文件名
//返回字符串
//http://r9c3yzgt4.hd-bkt.clouddn.com/ 外链 +文件名
return url+putRet.hash ;
} catch (Exception e) {
e.printStackTrace();
}
return null ;
}
}
5.在所需上传工具的控制层中注入工具类,并编写对应的上传方法
//注入UploadUtils
@Autowired
private UploadUtils uploadUtils ;
/**
* 图片上传
* @param multipartFile
* @return
*/
@RequestMapping("/upload")
public BaseResp upload(@RequestParam("file") MultipartFile multipartFile){
String url = uploadUtils.uploadFile(multipartFile);
//使用七牛云的工具类
return new BaseResp(0,"上传成功",null,url) ;
}
Shiro权限
shiro的初步使用
参考:
day74视频
1.引入shiro依赖
<!--导入shiro的依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.4.0</version>
</dependency>
2.Shiro的基础使用-->角色认证流程
#1.创建.ini配置文件
#配置用户信息,可配置多个用户
[users]
#用户名=密码
zhangsan=123
//2.shiro的认证流程
package com.j2113;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
@SpringBootTest
class SpringbootApplicationTests {
@Test
void contextLoads() {
}
@Test
void testFirstShiro() {
// 1)读取firstshiro.ini文件
//工厂对象
IniSecurityManagerFactory iniSecurityManagerFactory =
new IniSecurityManagerFactory("classpath:firstshiro.ini") ;
// 2)创建安全管理器实例
SecurityManager instance = iniSecurityManagerFactory.getInstance();
// 3)通过该安全 管理工具类 SecurityUtils 设置安全管理器
SecurityUtils.setSecurityManager(instance);
// 4)在通过SecurityUtils安全管理工具获取Subject
//前端发过来的数据,获取主体
Subject subject = SecurityUtils.getSubject();
// 5)模拟数据
// 给定用户名和密码(假数据),本来应该是从上一步获得的主体中获取用户名和密码
String username = "zhangsan";
String password = "123" ;
// 6)创建token将用户名和密码存在凭据管理器中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 7)主体Subject进行登录操作
// subject对象.login(凭据管理器中)
try{
subject.login(token);
// 出现异常:
// 如果用户名不存在,UnknownAccountException
// 如果密码错误,抛出异常 IncorrectCredentialsException
}catch (IncorrectCredentialsException e){ //获取到的密码信息不一致
System.out.println("密码错误!");
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}
// 8)认证成功---提示"登录成功"
//用户名,密码正确,认证成功,boolean isAuthenticated() 返回值就是true
if(subject.isAuthenticated()){
System.out.println("登录成功!");
}
}
}
3.基础使用-->角色认证和判断权限
#1.配置信息
#配置用户信息
[users]
#用户名=密码,角色(可跟多个角色)
zhangsan=123,normal
gaoyuanyuan=111,admin,normal
#配置角色
#角色=权限列表
[roles]
#超级管理员
admin=select,delete,update,insert
#普通管理员
normal=select
//2.shiro的角色认证和判断权限
@Test
void testShiroPermission() {
// 1)读取firstshiro.ini文件
//工厂对象
IniSecurityManagerFactory iniSecurityManagerFactory =
new IniSecurityManagerFactory("classpath:shiropermission_02.ini") ;
// 2)创建安全管理器实例
SecurityManager instance = iniSecurityManagerFactory.getInstance();
// 3)通过该安全 管理工具类 SecurityUtils 设置安全管理器
SecurityUtils.setSecurityManager(instance);
// 4)在通过SecurityUtils安全管理工具获取Subject
//前端发过来的数据,获取主体
Subject subject = SecurityUtils.getSubject();
// 5)模拟数据
// 给定用户名和密码(假数据)
String username = "zhangsan";
String password = "123" ;
/* String username = "gaoyuanyuan" ;
String password = "111" ;*/
// 6)创建token将用户名和密码存在凭据管理器中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 7)主体Subject进行登录操作
// subject对象.login(凭据管理器中)
try{
subject.login(token);
// 出现异常:
// 如果用户名不存在,UnknownAccountException
// 如果密码错误,抛出异常 IncorrectCredentialsException
}catch (IncorrectCredentialsException e){ //获取到的密码信息不一致
System.out.println("密码错误!");
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}
// 8)认证成功---提示"登录成功"
//用户名,密码正确,认证成功,boolean isAuthenticated() 返回值就是true
if(subject.isAuthenticated()){
System.out.println("登录成功!");
}
System.out.println("================================================================");
//授权权限,前提,登录了
//从主体中获取权限信息,判断是否有对应的权限
//boolean isPermitted(String var1);
boolean permittedFlag = subject.isPermitted("update"); //从主体中判断这个是否有指定的权限
if(permittedFlag){
System.out.println("当前用户有这个权限");
}else{
System.out.println("该用户没有这个权限");
}
System.out.println("-----------------------------------------------") ;
//授权:里面传入权限操作的数组,用户是这些权限中的哪 一个权限是可以是使用的
//boolean[] isPermitted(String... var1);
boolean[] permittedFlags = subject.isPermitted("select", "update", "delete", "insert");
//----数组---字符串
System.out.println(Arrays.toString(permittedFlags));
System.out.println("-----------------------------------------------") ;
//当前用户必须全部满足这些权限,有一个不能操作的权限,返回false,如果都满足,就返回true
//boolean isPermittedAll(String... var1);
boolean permittedAllFlag = subject.isPermittedAll("select", "update", "delete", "insert");
System.out.println(permittedAllFlag);
// subject.isPermitted(可以存储List集合对象<Permission实体:权限>)
System.out.println("========================================================================") ;
//查看当前这个用户角色
//判断用户的角色是否为"normal":普通管理员
// boolean hasRole(String var1);主体获取用户,对角色进行判断
// boolean normalFlag = subject.hasRole("normal");
boolean normalFlag = subject.hasRole("admin");
System.out.println(normalFlag);
System.out.println("-----------------------------------------------------------") ;
//boolean[] hasRoles(List<String> var1):从集合中判断用户的角色
List list = new ArrayList<>() ;
list.add("normal") ;
list.add("admin") ;
boolean[] booleans = subject.hasRoles(list);
System.out.println(Arrays.toString(booleans));
}
4.基础使用-->自定义安全策略Realm
//1.创建一个自定义安全策略配置类
package com.qf.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import java.util.HashSet;
import java.util.Set;
/**
* @author Kuke
* @date 2022/4/12 16:03
* 1)自定义一个类安全策略,完成认证和授权 要实继承一个AuthorizingRealm 重写两个方法
*
* 2)在resources下面配置ini文件,没有具体的用户信息以及权限信息 ,需要在MyRealam中进行认证和授权
* ini配置文件在下一个代码块
*
* MyRealm需要交给安全管理器 SecurityManager
*
*/
public class MyRealm extends AuthorizingRealm {
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("进入授权方法了....");
//用户认证成功之后,需要对用设置它的权限和角色
//获取前台的用户名
String username = (String) principalCollection.getPrimaryPrincipal();
//设置权限信息
//以后五张表联查 :直接查出权限信息----执行数据库
//现在用模拟数据,来表示查询出来的权限信息
Set set = new HashSet<>() ; //set集合最大的特点就是不重复
set.add("select") ;
set.add("update") ;
set.add("insert") ;
set.add("delete") ;
//创建授权的对象
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo() ;
//添加权限
//public void setStringPermissions(Set<String> stringPermissions)
simpleAuthorizationInfo.setStringPermissions(set) ;
//添加角色
simpleAuthorizationInfo.addRole("admin"); //添加admin 超级管理员
return simpleAuthorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
System.out.println("进入了认证方法....");
//从token中获取前端传过来的用户名
// Object getPrincipal();
String username = (String) authenticationToken.getPrincipal();
//从数据库获取真实信息---密码
//mybatis查询操作
String password = "123" ; //模拟数据
//这块进行比对
//创建SimpleAuthenticationInfo:认证器对象
//参数1:前端用户信息
//参数2:数据库查询的信息
//参数3:自定义安全策略类的标识
// public SimpleAuthenticationInfo(Object principal, Object credentials, String realmName) {
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
username,password,this.getName()
) ;
//认证完成
return simpleAuthenticationInfo;
}
}
#ini配置文件
#配置核心信息
#配置自定义的安全策略类
[main]
myRealm=com.qf.shiro.MyRealm
#把myRealm交给安全管理器
#管理多个realm
securityManager.realms=$myRealm
package com.qf;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Kuke
* @date 2022/4/12 14:49
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiroRealm {
/**
* 模拟数据,测试shiro认证
*/
@SuppressWarnings("all")
@Test
public void testShiroRealm(){
// 1)读取firstshiro.ini文件
//工厂对象
IniSecurityManagerFactory iniSecurityManagerFactory =
new IniSecurityManagerFactory("classpath:shirorealm_03.ini") ;
// 2)创建安全管理器实例
SecurityManager instance = iniSecurityManagerFactory.getInstance();
// 3)通过该安全 管理工具类 SecurityUtils 设置安全管理器
SecurityUtils.setSecurityManager(instance);
// 4)在通过SecurityUtils安全管理工具获取Subject
//前端发过来的数据,获取主体
Subject subject = SecurityUtils.getSubject();
// 5)模拟数据
// 给定用户名和密码(假数据)
String username = "zhangsan";
String password = "123" ;
// 6)创建token将用户名和密码存在凭据管理器中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 7)主体Subject进行登录操作
// subject对象.login(凭据管理器中)
try{
subject.login(token);
// 出现异常:
// 如果用户名不存在,UnknownAccountException
// 如果密码错误,抛出异常 IncorrectCredentialsException
}catch (IncorrectCredentialsException e){ //获取到的密码信息不一致
System.out.println("密码错误!");
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}
// 8)认证成功---提示"登录成功"
//用户名,密码正确,认证成功,boolean isAuthenticated() 返回值就是true
if(subject.isAuthenticated()){
System.out.println("登录成功!");
}
System.out.println("========================================================");
//授权认证
//授权权限,前提,登录了
//从主体中获取权限信息,判断是否有对应的权限
//boolean isPermitted(String var1);
boolean permittedFlag = subject.isPermitted("update"); //从主体中判断这个是否有指定的权限
if(permittedFlag){
System.out.println("当前用户有这个权限");
}else{
System.out.println("该用户没有这个权限");
}
System.out.println("-----------------------------------------------") ;
//授权:里面传入权限操作的数组,用户是这些权限中的哪一个权限是可以是使用的
//boolean[] isPermitted(String... var1);
boolean[] permittedFlags = subject.isPermitted("select", "update", "delete", "insert");
//----数组---字符串
System.out.println(Arrays.toString(permittedFlags));
System.out.println("-----------------------------------------------") ;
//当前用户必须全部满足这些权限,有一个不能操作的权限,返回false,如果都满足,就返回true
//boolean isPermittedAll(String... var1);
boolean permittedAllFlag = subject.isPermittedAll("select", "update", "delete", "insert");
System.out.println(permittedAllFlag);
// subject.isPermitted(可以存储List集合对象<Permission实体:权限>)
System.out.println("========================================================================") ;
//查看当前这个用户角色
//判断用户的角色是否为"normal":普通管理员
// boolean hasRole(String var1);主体获取用户,对角色进行判断
// boolean normalFlag = subject.hasRole("normal");
boolean normalFlag = subject.hasRole("admin") ;
System.out.println(normalFlag);
System.out.println("-----------------------------------------------------------") ;
//boolean[] hasRoles(List<String> var1):从集合中判断用户的角色
List list = new ArrayList<>() ;
list.add("normal") ;
list.add("admin") ;
boolean[] booleans = subject.hasRoles(list);
System.out.println(Arrays.toString(booleans));
}
}
5.基础使用-->MD5加密,进行认证
#定义凭证匹配器
[main]
#设置散列算法
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
#设置加密方式md5
credentialsMatcher.hashAlgorithmName=md5
#设置散列次数
#将凭证匹配器设置到realm
credentialsMatcher.hashIterations=1024
myRealm=com.qf.shiro.MyRealmMd5
#密码匹配器
myRealm.credentialsMatcher=$credentialsMatcher
#将myRealm交给安全管理器
securityManager.realms=$myRealm
//自定义安全策略
package com.j2113.shiro;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import java.util.HashSet;
import java.util.Set;
/**
* @author Kuke
* @date 2022/4/12 16:03
* 1)自定义一个类安全策略,完成认证和授权 要实继承一个AuthorizingRealm 覆盖两个方法
*
* 2)在resources下面配置ini文件,没有具体的用户信息以及权限信息 ,需要在MyRealam中进行认证和授权
* MyRealm需要交给安全管理器 SecurityManager
*
*/
public class MyRealmMd5 extends AuthorizingRealm {
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
System.out.println("进入了认证方法....");
//从token中获取前端传过来的用户名
// Object getPrincipal();
String username = (String) authenticationToken.getPrincipal();
//mybatis查询操作
// String password = "123" ;
//从数据库查出来的加密的密码(加密1024次)--"加盐"
String password = "663792ce1af229a8e24ce74bc713f605" ; //这里是模拟从数据库取出加密后的用户密码
//参数1:从前端传过来的用户名,
//参数2:密码
//参数3:"加盐的字符串"
//参数4:自定义安全策略类中的标识
// public SimpleAuthenticationInfo(Object principal, Object hashedCredentials, ByteSource credentialsSalt, String realmName)
SimpleAuthenticationInfo simpleAuthenticationInfo =
new SimpleAuthenticationInfo(
username,password, ByteSource.Util.bytes("qianfeng"),this.getName()
) ;
//认证完成
return simpleAuthenticationInfo;
}
}
//测试,MD5加密后认证
package com.j2113;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
/**
* @author Kuke
* @date 2022/4/12 14:49
*/
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestShiroRealmMd5 {
/**
* 模拟数据,测试shiro认证
*/
@Test
public void testShiroRealm(){
// 1)读取firstshiro.ini文件
//工厂对象
IniSecurityManagerFactory iniSecurityManagerFactory =
new IniSecurityManagerFactory("classpath:shiro-realm-md5_04.ini") ;
// 2)创建安全管理器实例
SecurityManager instance = iniSecurityManagerFactory.getInstance();
// 3)通过该安全 管理工具类 SecurityUtils 设置安全管理器
SecurityUtils.setSecurityManager(instance);
// 4)在通过SecurityUtils安全管理工具获取Subject
//前端发过来的数据,获取主体
Subject subject = SecurityUtils.getSubject();
// 5)模拟数据
// 给定用户名和密码(假数据)
String username = "zhangsan";
String password = "123" ;
// 6)创建token将用户名和密码存在凭据管理器中
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
// 7)主体Subject进行登录操作
// subject对象.login(凭据管理器中)
try{
subject.login(token);
// 出现异常:
// 如果用户名不存在,UnknownAccountException
// 如果密码错误,抛出异常 IncorrectCredentialsException
}catch (IncorrectCredentialsException e){ //获取到的密码信息不一致
System.out.println("密码错误!");
}catch (UnknownAccountException e){
System.out.println("用户不存在");
}
// 8)认证成功---提示"登录成功"
//用户名,密码正确,认证成功,boolean isAuthenticated() 返回值就是true
if(subject.isAuthenticated()){
System.out.println("登录成功!");
}
}
}
SpringBoot整合Shiro的认证流程
参考:
day75视频
1.引入依赖
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring-boot-web-starter</artifactId>
<version>1.6.0</version>
</dependency>
2.在原本的properties文件中加入配置,或者重新创建yml配置文件
# 应用名称
spring.application.name=shiro_01
# 应用服务 WEB 访问端口
server.port=8080
#下面这些内容是为了让MyBatis映射
#指定Mybatis的Mapper文件
mybatis.mapper-locations=classpath:mappers/*xml
#指定Mybatis的实体目录
mybatis.type-aliases-package=com.j2113.pojo
# 数据库驱动:
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
# 数据源名称
spring.datasource.name=defaultDataSource
# 数据库连接地址
spring.datasource.url=jdbc:mysql://localhost:3306/j2113?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
# 数据库用户名&密码:
spring.datasource.username=root
spring.datasource.password=981229
#JPA配置
spring.jpa.show-sql=true
spring.jpa.database=mysql
spring.jpa.hibernate.ddl-auto=update
#yml配置文件
#配置端口号
server:
port: 8080
#配置数据源数据库的连接信息
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/j2113?characterEncoding=utf8&useSSL=false&serverTimezone=UTC
username: root
password: 981229
#配置jpa的信息
jpa:
#显示sql语句
show-sql: true
#mysql类型
database: mysql
#具体详情可以看上面的 “SpringBoot整合Spring Data JPA”
hibernate:
ddl-auto: update
#配置mybatis
mybatis:
mapper-locations: classpath:mappers/*xml
type-aliases-package: com.j2113.pojo
3.在业务层service时,来进行权限管理
package com.j2113.service.impl;
import com.j2113.pojo.User;
import com.j2113.repository.UserRepository;
import com.j2113.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.service.impl
* @ClassName: UserServiceImpl
* @Project_Path: com.j2113.service.impl.UserServiceImpl
* @Author: YHaooo
* @CreateTime: 2022-04-13 18:56
* @Description: TODO
*/
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserRepository userRepository;
@Override
public String userLogin(User user) {
//需要通过Spring的配置类(对应ShrioConfig配置类),配置realm,
// ---交给安全管理器 securityManaget
// --->securityManaget交给shiro的过滤器
//直接要从SecurityUtils安全工具类中获取主体
Subject subject = SecurityUtils.getSubject();
//创建token对象,凭据管理器
//存储前台出来过的用户名和密码
UsernamePasswordToken usernamePasswordToken =
new UsernamePasswordToken(user.getUserName(),user.getUserPassword()) ;
//主体进行登录,同时判断是否认证成功
//登录---->走到realm中的认证方法中
try{
subject.login(usernamePasswordToken);//主体进行login就是比对前台用户信息是否能够查到用户密码
}catch (IncorrectCredentialsException e){
return "密码错误!" ;
}catch(UnknownAccountException e){
return "用户名不存在" ;
}
if(subject.isAuthenticated()){
return "登录成功" ;
}
return "登录失败";
}
}
4.创建自定义安全策略类Realm
package com.j2113.shiro;
import com.j2113.pojo.User;
import com.j2113.repository.UserRepository;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.shiro
* @ClassName: MyRealm
* @Project_Path: com.j2113.shiro.MyRealm
* @Author: YHaooo
* @CreateTime: 2022-04-13 19:19
* @Description: TODO 自定义安全策略
*/
@Component
public class MyRealm extends AuthorizingRealm {
//注入userRepository
@Autowired
private UserRepository userRepository ;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("进入认证方法...");
//获取前端传递过来的用户名
String userName = (String) authenticationToken.getPrincipal();
//通过用户名查询数据中的用户实体
User byUserName = userRepository.findByUserName(userName);
//判断如果者用户不为空,存在
if(byUserName!=null){
//获取它的密码
String userPassword = byUserName.getUserPassword();
//创建认证器
//密码不加盐
//参数1:前端传过来的用户名
//参数2:通过数据库查出来的用户密码
//参数3:自定义的realm的标识
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userName,userPassword,this.getName()) ;
return authenticationInfo ;
}
return null;
}
}
5.创建shiro配置类文件
package com.j2113.config;
import com.j2113.shiro.MyRealm;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.config
* @ClassName: ShiroConfig
* @Project_Path: com.j2113.config.ShiroConfig
* @Author: YHaooo
* @CreateTime: 2022-04-13 19:28
* @Description: TODO shiro的配置类,代替的是之前的ini文件
*/
//标记它是一个配置类
@Configuration
public class ShiroConfig {
//1.配置realm
@Bean(name = "realm")
public MyRealm myRealm() {
return new MyRealm();
}
//2.配置securityManager,设置realm
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") MyRealm myRealm) {
//创建安全管理器实现类对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//将realm对象添加到安全管理器中
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//3.配置shiro过滤器,设置安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
//创建ShiroFilterFactoryBean:shiro过滤器的工厂
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//defaultWebSecurityManager
//public void setSecurityManager(SecurityManager securityManage){}
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
return shiroFilterFactoryBean;
}
}
6.完成controller编写,运行项目。可使用swagger2进行接口测试
SpringBoot整合Shiro的授权流程
与认证的步骤基本相同,只展示新增的代码
1.创建权限实体,mapper,mapper.xml,controller
//创建权限实体,mapper,mapper.xml,controller
//pojo
@Data
public class TbPermission {
private Integer permissionid ;
private String permission_name ;
}
//mapper
@Mapper
public interface PermissionMapper {
List<TbPermission> findPermissionsByName(@Param("name") String username) ;
}
//mapper.xml
<mapper namespace="com.j2113.mapper.PermissionMapper">
<select id="findPermissionsByName" resultType="tbpermission">
select tp.*
from tb_user tu,
tb_user_role tur,
tb_role tr,
tb_role_permission trp,
tb_permission tp --
where tu.id = tur.userid
AND tur.roleid = tr.id
AND tr.id = trp.roleid
and trp.perid = tp.id
and tu.user_name = #{name}
</select>
</mapper>
//controller
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping(value = "/login")
public String login(@RequestBody User user) {
System.out.println("user = " + user);
return userService.userLogin(user);
}
@GetMapping("/toLogin")
public String toLogin(){
return "未登录,请先登录" ;
}
}
@RestController
@RequestMapping("/auth")
public class TestController {
@RequestMapping("/one")
public String one(){
return "ok" ;
}
@RequestMapping("/two")
public String two(){
return "ok" ;
}
@RequestMapping("/three")
public String three(){
return "ok" ;
}
@RequestMapping("/noAuth")
public String noAuth(){
return "对不起,你没有权限" ;
}
}
2.自定义安全策略,新增授权代码
//自定义安全策略,新增授权代码
package com.j2113.shiro;
import com.j2113.mapper.PermissionMapper;
import com.j2113.pojo.TbPermission;
import com.j2113.pojo.User;
import com.j2113.repository.UserRepository;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.shiro
* @ClassName: MyRealm
* @Project_Path: com.j2113.shiro.MyRealm
* @Author: YHaooo
* @CreateTime: 2022-04-13 19:19
* @Description: TODO 自定义安全策略
*/
@Component
public class MyRealm extends AuthorizingRealm {
//注入userRepository
@Autowired
private UserRepository userRepository ;
//注入PermissionMapper
@Autowired
private PermissionMapper permissionMapper ;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权");
//需要获取前端过来的用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
//查询这个用户所有的权限信息
List<TbPermission> permissionsList = permissionMapper.findPermissionsByName(userName);
//创建set集合,存储权限信息
Set set = new HashSet<>() ;
for (TbPermission tbPermission : permissionsList) {
//权限名称
set.add(tbPermission.getPermission_name()) ;
}
//创建授权器对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo() ;
authorizationInfo.setStringPermissions(set);
return authorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("进入认证方法...");
//获取前端传递过来的用户名
String userName = (String) authenticationToken.getPrincipal();
//通过用户名查询数据中的用户实体
User byUserName = userRepository.findByUserName(userName);
//判断如果者用户不为空,存在
if(byUserName!=null){
//获取它的密码
String userPassword = byUserName.getUserPassword();
//创建认证器
//密码不加盐
//参数1:前端传过来的用户名
//参数2:通过数据库查出来的用户密码
//参数3:自定义的realm的标识
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userName,userPassword,this.getName()) ;
// //加入密码加盐
// SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
// userName,userPassword, ByteSource.Util.bytes(byUserName.getUser_name()),
// this.getName()) ;
return authenticationInfo ;
}
return null;
}
}
3.shiro配置类,新增权限相关代码
//shiro配置类,新增权限相关代码
//标记它是一个配置类
@Configuration
public class ShiroConfig {
//1.配置realm
@Bean(name = "realm")
public MyRealm myRealm() {
return new MyRealm();
}
//2.配置securityManager,设置realm
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") MyRealm myRealm) {
//创建安全管理器实现类对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//将realm对象添加到安全管理器中
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//3.配置shiro过滤器,设置安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
//创建ShiroFilterFactoryBean:shiro过滤器的工厂
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//defaultWebSecurityManager
//public void setSecurityManager(SecurityManager securityManage){}
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
//配置用户访问的接口地址和权限一一对应
//创建Map集合
Map map = new HashMap<>() ;
//配置接口地址对应的权限: perms[权限名称]
map.put("/auth/one","perms[findAll]") ;
map.put("/auth/two","perms[update,delete,insert]") ;
map.put("/auth/three","perms[findAll,update,delete,insert]") ;
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
// 设置用户未登录的链路地址
shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
// 设置用户没有权限的访问路径地址
// shiroFilterFactoryBean.setUnauthorizedUrl(请求路径);
shiroFilterFactoryBean.setUnauthorizedUrl("/auth/noAuth");
return shiroFilterFactoryBean;
}
}
SpringBoot整合Shiro基于注解
1.自定义安全策略Realm不变
2.Shiro配置类,去除无用设置权限代码,新增开启注解模式
//标记它是一个配置类
@Configuration
public class ShiroConfig {
//1.配置realm
@Bean(name = "realm")
public MyRealm myRealm() {
return new MyRealm();
}
//2.配置securityManager,设置realm
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") MyRealm myRealm) {
//创建安全管理器实现类对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//将realm对象添加到安全管理器中
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//3.配置shiro过滤器,设置安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
//创建ShiroFilterFactoryBean:shiro过滤器的工厂
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//defaultWebSecurityManager
//public void setSecurityManager(SecurityManager securityManage){}
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
/* //配置用户访问的接口地址和权限一一对应
//创建Map集合
Map map = new HashMap<>() ;
//配置接口地址对应的权限: perms[权限名称]
map.put("/auth/one","perms[findAll]") ;
map.put("/auth/two","perms[update,delete,insert]") ;
map.put("/auth/three","perms[findAll,update,delete,insert]") ;
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);*/
/*// 设置用户未登录的链路地址
shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
// 设置用户没有权限的访问路径地址
// shiroFilterFactoryBean.setUnauthorizedUrl(请求路径);
shiroFilterFactoryBean.setUnauthorizedUrl("/auth/noAuth");*/
return shiroFilterFactoryBean;
}
//开启SpringBoot和Shiro整合的注解模式
//1)依赖于Spring的AOP ---配置授权的通知,设置安全管理器
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
//创建通知对象
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new
AuthorizationAttributeSourceAdvisor() ;
//设置安全管理器
// public void setSecurityManager(SecurityManager securityManager)
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
//返回授权通知对象
return authorizationAttributeSourceAdvisor ;
}
//2)开启自动代理,必须结合第一步Spring和shiro的通知对象使用!
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
//创建代理对象(内置shiro里面代理对象)
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator() ;
//开启自动代理,参数设置为true
//public void setProxyTargetClass(boolean proxyTargetClass) {
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator ;
}
}
3.在controller层加入权限注解
package com.qf.controller;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @author Kuke
* @date 2022/4/13 14:27
* 测试下授权
*/
@RestController
@RequestMapping("/auth")
public class TestController {
//加入一些权限注解
@RequiresPermissions("findAll") //查询权限
@RequestMapping("/one")
public String one(){
return "ok" ;
}
@RequiresPermissions(value = {"update","delete","insert"})
@RequestMapping("/two")
public String two(){
return "ok" ;
}
@RequiresPermissions(value = {"findAll","update","delete","insert"})
@RequestMapping("/three")
public String three(){
return "ok" ;
}
@RequestMapping("/noAuth")
public String noAuth(){
return "对不起,你没有权限" ;
}
}
4.创建权限异常捕捉器
package com.j2113.controller;
import org.apache.shiro.authz.AuthorizationException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
/**
* @author Kuke
* @date 2022/4/13 15:54
*
*/
//标记这个类是异常捕捉类,当前发生异常的时候,注解走配置的异常捕捉器,提示信息
@ControllerAdvice
//加入一个注解
@ResponseBody
public class ExceptionController {
@ExceptionHandler(AuthorizationException.class)//AuthorizationException授权异常
public String noAuth(){
return "没有权限" ;
}
}
SpringBoot整合Shiro基于注解,并加入MD5加密
1.自定义安全策略,去除不加密的认证器,新增使用加密的认证器
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.shiro
* @ClassName: MyRealm
* @Project_Path: com.j2113.shiro.MyRealm
* @Author: YHaooo
* @CreateTime: 2022-04-13 19:19
* @Description: TODO 自定义安全策略
*/
@Component
public class MyRealm extends AuthorizingRealm {
//注入userRepository
@Autowired
private UserRepository userRepository ;
//注入PermissionMapper
@Autowired
private PermissionMapper permissionMapper ;
/**
* 授权
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
System.out.println("执行授权");
//需要获取前端过来的用户名
String userName = (String) principalCollection.getPrimaryPrincipal();
//查询这个用户所有的权限信息
List<TbPermission> permissionsList = permissionMapper.findPermissionsByName(userName);
//创建set集合,存储权限信息
Set set = new HashSet<>() ;
for (TbPermission tbPermission : permissionsList) {
//权限名称
set.add(tbPermission.getPermission_name()) ;
}
//创建授权器对象
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo() ;
authorizationInfo.setStringPermissions(set);
return authorizationInfo;
}
/**
* 认证
* @param authenticationToken
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
System.out.println("进入认证方法...");
//获取前端传递过来的用户名
String userName = (String) authenticationToken.getPrincipal();
//通过用户名查询数据中的用户实体
User byUserName = userRepository.findByUserName(userName);
//判断如果者用户不为空,存在
if(byUserName!=null){
//获取它的密码
String userPassword = byUserName.getUserPassword();
//创建认证器
//密码不加盐
//参数1:前端传过来的用户名
//参数2:通过数据库查出来的用户密码
//参数3:自定义的realm的标识
// SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
// userName,userPassword,this.getName()) ;
//加入密码加盐
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userName,userPassword, ByteSource.Util.bytes(盐,大多使用用户名作为盐,即byUserName.getUserName()),
this.getName()) ;
return authenticationInfo ;
}
return null;
}
}
2.shiro配置类,去除原本的配置realm方法,新增加入新配置的realm方法和MD5配置
/**
* @Project_Name: 0413
* @Package_Name: com.j2113.config
* @ClassName: ShiroConfig
* @Project_Path: com.j2113.config.ShiroConfig
* @Author: YHaooo
* @CreateTime: 2022-04-13 19:28
* @Description: TODO shiro的配置类,代替的是之前的ini文件
*/
//标记它是一个配置类
@Configuration
public class ShiroConfig {
//1.配置realm
// @Bean(name = "realm")
// public MyRealm myRealm() {
// return new MyRealm();
// }
//如果配置md5加盐,需要修改MyRealm的配置
@Bean(name = "realm")
public MyRealm myRealm(@Qualifier("hashedCredentialsMatcher") HashedCredentialsMatcher hashedCredentialsMatcher){
MyRealm myRealm = new MyRealm();
//关闭shiro中密码验证方式
myRealm.setAuthenticationCachingEnabled(false);
//设置自定义的密码加密方式
myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
return myRealm;
}
//加盐--md5配置
/**
* MD5加密
* @return
*/
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher(){
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//指定加密方式为MD5
hashedCredentialsMatcher.setHashAlgorithmName("MD5");
//加密次数
hashedCredentialsMatcher.setHashIterations(1024);
//storedCredentialsHexEncoded默认是true,此时用的是密码加密用的是Hex编码;false时用Base64编码
hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);
return hashedCredentialsMatcher;
}
//2.配置securityManager,设置realm
@Bean(name = "defaultWebSecurityManager")
public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("realm") MyRealm myRealm) {
//创建安全管理器实现类对象
DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
//将realm对象添加到安全管理器中
defaultWebSecurityManager.setRealm(myRealm);
return defaultWebSecurityManager;
}
//3.配置shiro过滤器,设置安全管理器
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
//创建ShiroFilterFactoryBean:shiro过滤器的工厂
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//defaultWebSecurityManager
//public void setSecurityManager(SecurityManager securityManage){}
shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
/* //配置用户访问的接口地址和权限一一对应
//创建Map集合
Map map = new HashMap<>() ;
//配置接口地址对应的权限: perms[权限名称]
map.put("/auth/one","perms[findAll]") ;
map.put("/auth/two","perms[update,delete,insert]") ;
map.put("/auth/three","perms[findAll,update,delete,insert]") ;
shiroFilterFactoryBean.setFilterChainDefinitionMap(map);*/
/*// 设置用户未登录的链路地址
shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
// 设置用户没有权限的访问路径地址
// shiroFilterFactoryBean.setUnauthorizedUrl(请求路径);
shiroFilterFactoryBean.setUnauthorizedUrl("/auth/noAuth");*/
return shiroFilterFactoryBean;
}
//开启SpringBoot和Shiro整合的注解模式
//1)依赖于Spring的AOP ---配置授权的通知,设置安全管理器
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor
(@Qualifier("defaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
//创建通知对象
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new
AuthorizationAttributeSourceAdvisor() ;
//设置安全管理器
// public void setSecurityManager(SecurityManager securityManager)
authorizationAttributeSourceAdvisor.setSecurityManager(defaultWebSecurityManager);
//返回授权通知对象
return authorizationAttributeSourceAdvisor ;
}
//2)开启自动代理,必须结合下面的Spring和shiro的通知对象使用!
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
//创建代理对象(内置shiro里面代理对象)
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator() ;
//开启自动代理,参数设置为true
//public void setProxyTargetClass(boolean proxyTargetClass) {
defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
return defaultAdvisorAutoProxyCreator ;
}
}
3.记得修改数据库用户密码为加密后的密码,还可添加密码加密方法
//明文密码MD5加密方法,用于之后注册功能给明文密码加密
public class MD5Salt {
public static void main(String[] args) {
//加密算法
String hashAlgorithName = "MD5"; //加密方式
//密码
String password = "123";
//加密次数
int hashIterations =1024;
//使用登录名做为salt (通常情况使用用户登录的名称 作为"盐"),或者使用固定的一些通用字符串作为"盐"值
ByteSource credentialsSalt = ByteSource.Util.bytes("qianfeng");
//参数:加密方式,用户明文密码,盐,加密次数
SimpleHash simpleHash = new SimpleHash(hashAlgorithName, password, credentialsSalt, hashIterations);
System.out.println("ok:"+simpleHash);
}
}
Vue
两种方式传参
methods: {
sendcode: function () {
axios.post("http://localhost:8081/user/sendmail",{"email":this.userreg.uaccount}).then((result) => {
alert(123)
}).catch((err) => {
});
// axios({url:"http://localhost:8081/user/sendmail",method:"post",params:{email:this.userreg.uaccount}})
// .then((res) => {
// alert(123)
// }).catch((err) => {
// });
},
},
后端接参
//邮件激活
@PostMapping(value = "/sendmail")
public BaseResp sendMail(@RequestBody Map map, HttpSession session) {
System.out.println(map.get("email"));
return userService.sendMail(map.get("email"),session) ;
}
// //邮件激活
// @PostMapping(value = "/sendmail")
// public BaseResp sendMail(String email, HttpSession session) {
// System.out.println("email = " + email);
// return userService.sendMail(email,session) ;
// }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理