这是我参与8月更文挑战的第四天,活动详情查看:8月更文挑战
1.1 SpringBoot
这个就没什么好说的了,能看到这个教程的,估计都是可以说精通了SpringBoot
的使用
1.2 Shiro
一个安全框架,但不只是一个安全框架。它能实现多种多样的功能。并不只是局限在web层。在国内的市场份额占比高于SpringSecurity
,是使用最多的安全框架
可以实现用户的认证和授权。比SpringSecurity
要简单的多。
1.3 Jwt
我的理解就是可以进行客户端与服务端之间验证的一种技术,取代了之前使用Session来验证的不安全性
为什么不适用Session?
原理是,登录之后客户端和服务端各自保存一个相应的SessionId,每次客户端发起请求的时候就得携带这个SessionId来进行比对
- Session在用户请求量大的时候服务器开销太大了
- Session不利于搭建服务器的集群(也就是必须访问原本的那个服务器才能获取对应的SessionId)
它使用的是一种令牌技术
Jwt字符串分为三部分
- Header
存储两个变量
1. 秘钥(可以用来比对)
2. 算法(也就是下面将Header和payload加密成Signature)
- payload
存储很多东西,基础信息有如下几个
1. 签发人,也就是这个“令牌”归属于哪个用户。一般是`userId`
2. 创建时间,也就是这个令牌是什么时候创建的
3. 失效时间,也就是这个令牌什么时候失效
4. 唯一标识,一般可以使用算法生成一个唯一标识
- Signature
这个是上面两个经过Header中的算法加密生成的,用于比对信息,防止篡改Header和payload
然后将这三个部分的信息经过加密生成一个JwtToken
的字符串,发送给客户端,客户端保存在本地。当客户端发起请求的时候携带这个到服务端(可以是在cookie
,可以是在header
,可以是在localStorage
中),在服务端进行验证
好了,废话不多说了,下面开始实战,实战分为以下几个部分
SpringBoot
整合Shiro
SpringBoot
整合Jwt
SpringBoot
+Shiro
+Jwt
1 | xml复制代码 <dependency> |
两种方式:
- 将ssm的整合的配置使用java代码方式在springBoot中写一遍
- 使用官方提供的start
2.1 使用start整合springBoot
pom.xml
1 | xml复制代码<dependency> |
application.properties
1 | ini复制代码shiro.loginUrl="xxx" |
创建ShiroConfig.java进行一些简单的配置
1 | java复制代码@Configuration |
创建自定义的Realm
1 | csharp复制代码public class CustomRealm extends AuthorizingRealm { |
2.2 不使用starter
1 | xml复制代码<!-- 自动依赖导入 shiro-core 和 shiro-web --> |
编写 Shiro 的配置类:ShiroConfig
将 Shiro 的配置信息(spring-shiro.xml 和 spring-web.xml)以 Java 代码配置的形式改写:
1 | typescript复制代码@Configuration |
编写 Controller
与 Shiro 和 SSM 的整合一样。略
编写 Thymeleaf 页面
略
3.1 依赖
1 | markdown复制代码1. springboot |
3.2 代码
- 创建JwtUtil
1 | java复制代码package cn.coderymy.utils; |
解析:
1. 在创建JwtUtil对象的时候需要传入几个数值
1. 这个用户,用来生成秘钥
2. 这个加密算法,用来加密生成jwt
2. 通过jwt数据获取用户信息的方法(decode())
3. 判断jwt是否存在或者过期的方法
4. 最后是测试方法
- 创建一个Controller
1. 登录的Controller
1. 获取username和password,进行与数据库的校验,校验成功执行下一步,失败直接返回
2. 使用创建JwtUtil对象,传入username和需要使用的加密算法
3. 创建需要加在载荷中的一些基本信息的一个map对象
4. 创建jwt数据,传入username,保存时间,以及基本信息的map对象
2. 校验Controller
1. 获取前台传入的Jwt数据
2. 使用`JWTUtil`中的`isVerify`进行该jwt数据有效的校验
- 由于需要对shiro的SecurityManager进行设置,所以不能使用shiro-spring-boot-starter进行与springboot的整合,只能使用spring-shiro
1 | xml复制代码<!-- 自动依赖导入 shiro-core 和 shiro-web --> |
- 由于需要实现无状态的web,所以使用不到Shiro的Session功能,严谨点就是将其关闭
1 | java复制代码public class JwtDefaultSubjectFactory extends DefaultWebSubjectFactory { |
这样如果调用getSession()
方法会抛出异常
4.1 流程
- 用户请求,不携带token,就在JwtFilter处抛出异常/返回没有登录,让它去登陆
- 用户请求,携带token,就到JwtFilter中获取jwt,封装成JwtToken对象。然后使用JwtRealm进行认证
- 在JwtRealm中进行认证判断这个token是否有效,也就是
1 | markdown复制代码执行流程:1. 客户端发起请求,shiro的过滤器生效,判断是否是login或logout的请求<br/> 如果是就直接执行请求<br/> 如果不是就进入JwtFilter2. JwtFilter执行流程 1. 获取header是否有"Authorization"的键,有就获取,没有就抛出异常 2. 将获取的jwt字符串封装在创建的JwtToken中,使用subject执行login()方法进行校验。这个方法会调用创建的JwtRealm 3. 执行JwtRealm中的认证方法,使用`jwtUtil.isVerify(jwt)`判断是否登录过 4. 返回true就使基础执行下去 |
4.2 快速开始
0. JwtDeafultSubjectFactory
1 | java复制代码package cn.coderymy.shiro; |
1. 创建JwtUtil
这个一般是固定的写法,其中写了大量注释
1 | java复制代码package cn.coderymy.util; |
2. 创建JwtFilter
也就是在Shiro的拦截器中多加一个,等下需要在配置文件中注册这个过滤器
1 | java复制代码package cn.coderymy.filter; |
3. 创建JwtToken
其中封装了需要传递的jwt
字符串
1 | java复制代码package cn.coderymy.shiro; |
4. JwtRealm
创建判断jwt
是否有效的认证方式的Realm
1 | java复制代码package cn.coderymy.realm; |
5. ShiroConfig
配置一些信息
- 因为不适用Session,所以为了防止会调用getSession()方法而产生错误,所以默认调用自定义的Subject方法
- 一些修改,关闭SHiroDao等
- 注册JwtFilter
1 | java复制代码package cn.coderymy.config; |
6. 测试
1 | java复制代码package cn.coderymy.controller; |
4.3 授权方面的信息
在JwtRealm中的授权部分,可以使用JwtUtil.decode(jwt).get("username")
获取到username,使用username去数据库中查找到对应的权限,然后将权限赋值给这个用户就可以实现权限的认证了
本文转载自: 掘金