技术标签: spring boot 程序JAVA java jwt 程序
Jwt
全称是:json web token
。它将用户信息加密到token
里,服务器不保存任何用户信息。服务器通过使用保存的密钥验证token
的正确性,只要正确即通过验证。
URL
、POST
参数或者在HTTP header
发送,因为数据量小,传输速度也很快;Token
是以JSON
加密的形式保存在客户端的,所以JWT
是跨语言的,原则上任何web
形式都支持;Jwt
消息构成一个token
分3部分,按顺序为
header
)payload
)signature
)三部分之间用.
号做分隔。例如:
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOiIxYzdiY2IzMS02ODFlLTRlZGYtYmU3Yy0wOTlkODAzM2VkY2UiLCJleHAiOjE1Njk3Mjc4OTF9.wweMzyB3tSQK34Jmez36MmC5xpUh15Ni3vOV_SGCzJ8
Jwt
的头部承载两部分信息:
Jwt
HMAC SHA256
Jwt
里验证和签名使用的算法列表如下:
JWS | 算法名称 |
---|---|
HS256 | HMAC256 |
HS384 | HMAC384 |
HS512 | HMAC512 |
RS256 | RSA256 |
RS384 | RSA384 |
RS512 | RSA512 |
ES256 | ECDSA256 |
ES384 | ECDSA384 |
ES512 | ECDSA512 |
载荷就是存放有效信息的地方。基本上填2
种类型数据
由这2部分内部做base64
加密。
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
token
中存放的key-value
值Jwt
的第三部分是一个签证信息,这个签证信息由三部分组成base64
加密后的header
和base64
加密后的payload
连接组成的字符串,然后通过header
中声明的加密方式进行加盐secret
组合加密,然后就构成了Jwt
的第三部分。
Spring Boot
和Jwt
集成示例 <dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.10.3</version>
</dependency>
//需要登录才能进行操作的注解LoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginToken {
boolean required() default true;
}
//用来跳过验证的PassToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private String userID;
private String userName;
private String passWord;
}
package com.sky.springbootdemo.jwt.service;
import com.sky.springbootdemo.jwt.entity.User;
import org.springframework.stereotype.Service;
/**
* @title: UserService
* @Author gjt
* @Date: 2020-12-21
* @Description:
*/
@Service
public class UserService {
public User getUser(String userid, String password){
if ("admin".equals(userid) && "admin".equals(password)){
User user=new User();
user.setUserID("admin");
user.setUserName("admin");
user.setPassWord("admin");
return user;
}
else{
return null;
}
}
public User getUser(String userid){
if ("admin".equals(userid)){
User user=new User();
user.setUserID("admin");
user.setUserName("admin");
user.setPassWord("admin");
return user;
}
else{
return null;
}
}
}
package com.sky.springbootdemo.jwt.service;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.sky.springbootdemo.jwt.entity.User;
import org.springframework.stereotype.Service;
import java.util.Date;
/**
* @title: TokenService
* @Author gjt
* @Date: 2020-12-21
* @Description:
*/
@Service
public class TokenService {
/**
* 过期时间5分钟
*/
private static final long EXPIRE_TIME = 5 * 60 * 1000;
public String getToken(User user) {
Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
String token="";
token= JWT.create().withAudience(user.getUserID()) // 将 user id 保存到 token 里面
.withExpiresAt(date) //五分钟后token过期
.sign(Algorithm.HMAC256(user.getPassWord())); // 以 password 作为 token 的密钥
return token;
}
}
package com.sky.springbootdemo.jwt.interceptor;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.sky.springbootdemo.jwt.annotation.LoginToken;
import com.sky.springbootdemo.jwt.annotation.PassToken;
import com.sky.springbootdemo.jwt.entity.User;
import com.sky.springbootdemo.jwt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;
/**
* @title: JwtInterceptor
* @Author gjt
* @Date: 2020-12-21
* @Description:
*/
public class JwtInterceptor implements HandlerInterceptor{
@Autowired
private UserService userService;
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) throws Exception {
String token = httpServletRequest.getHeader("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if(!(object instanceof HandlerMethod)){
return true;
}
HandlerMethod handlerMethod=(HandlerMethod)object;
Method method=handlerMethod.getMethod();
//检查是否有passtoken注释,有则跳过认证
if (method.isAnnotationPresent(PassToken.class)) {
PassToken passToken = method.getAnnotation(PassToken.class);
if (passToken.required()) {
return true;
}
}
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent(LoginToken.class)) {
LoginToken loginToken = method.getAnnotation(LoginToken.class);
if (loginToken.required()) {
// 执行认证
if (token == null) {
throw new RuntimeException("无token,请重新登录");
}
// 获取 token 中的 user id
String userId;
try {
userId = JWT.decode(token).getAudience().get(0);
} catch (JWTDecodeException j) {
throw new RuntimeException("401");
}
User user = userService.getUser(userId);
if (user == null) {
throw new RuntimeException("用户不存在,请重新登录");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassWord())).build();
try {
jwtVerifier.verify(token);
} catch (JWTVerificationException e) {
throw new RuntimeException("401");
}
return true;
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
package com.sky.springbootdemo.jwt.config;
import com.sky.springbootdemo.jwt.interceptor.JwtInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @title: InterceptorConfig
* @Author gjt
* @Date: 2020-12-21
* @Description:
*/
@Configuration
public class InterceptorConfig implements WebMvcConfigurer{
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(jwtInterceptor())
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
//注册TestInterceptor拦截器
// InterceptorRegistration registration = registry.addInterceptor(jwtInterceptor());
// registration.addPathPatterns("/**"); //添加拦截路径
// registration.excludePathPatterns( //添加不拦截路径
// "/**/*.html", //html静态资源
// "/**/*.js", //js静态资源
// "/**/*.css", //css静态资源
// "/**/*.woff",
// "/**/*.ttf",
// "/swagger-ui.html"
// );
}
@Bean
public JwtInterceptor jwtInterceptor() {
return new JwtInterceptor();
}
}
package com.sky.springbootdemo.jwt.controller;
import com.alibaba.fastjson.JSONObject;
import com.sky.springbootdemo.jwt.annotation.LoginToken;
import com.sky.springbootdemo.jwt.entity.User;
import com.sky.springbootdemo.jwt.service.TokenService;
import com.sky.springbootdemo.jwt.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* @title: Login
* @Author gjt
* @Date: 2020-12-22
* @Description:
*/
@RestController
public class Login {
@Autowired
private UserService userService;
@Autowired
private TokenService tokenService;
@PostMapping("login")
public Object login(String username, String password){
JSONObject jsonObject=new JSONObject();
User user=userService.getUser(username, password);
if(user==null){
jsonObject.put("message","登录失败!");
return jsonObject;
}else {
String token = tokenService.getToken(user);
jsonObject.put("token", token);
jsonObject.put("user", user);
return jsonObject;
}
}
@LoginToken
@PostMapping("/getMessage")
public String getMessage(){
return "你已通过验证";
}
}
package com.sky.springbootdemo.jwt.controller;
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestControllerAdvice;
/**
* @title: GlobalExceptionHandler
* @Author gjt
* @Date: 2020-12-22
* @Description:
*/
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseBody
@ExceptionHandler(Exception.class)
public Object handleException(Exception e) {
String msg = e.getMessage();
if (msg == null || msg.equals("")) {
msg = "服务器出错";
}
JSONObject jsonObject = new JSONObject();
jsonObject.put("code", 1000);
jsonObject.put("message", msg);
return jsonObject;
}
}
postman测试
3.1、获取tockem
文章浏览阅读72次。教程本刷机包比一般的大,是因为同时适配recovery卡刷和酷卓一键刷机。但是刷进系统后和普通刷机包都是一样的。注意事项(务必细读) 联想 ZUK Z1 免解锁BL(bootloader),一键ROOT是保资料的,刷机是会清空数据的(无论如何都请备份重要数据)卡刷方法卡刷需要已经安装了twrp recovery,直接传入手机后用twrp recovery刷机,和普通刷机包使用无区别..._zukz1被root了怎么办
文章浏览阅读590次。一、题目 编写支持双端队列的例程,插入与弹出操作均花费 O(1)时间二、解答 双端队列(deque,全名double-ended queue)是一种具有队列和栈性质的数据结构。 双端队列中的元素可以从两端弹出,插入和删除操作限定在队列的两边进行。 基本操作:在双端队列两端插入与删除。 ADT术语: ..._编写算法实现双端队列。数据结构分析
文章浏览阅读4.2k次。centos7安装clion下载clion的linux包。上传到linux服务器下。scp -P 20211 E:\迅雷下载\cmake-3.14.3.tar.gz 用户名@服务器地址:/home/bob/解压并到解压的文件夹bin目录下。运行命令“./clion.sh”。(需在centos7图形界面模式下才能启动clion)启动之后还不能运行c语言程序,我们还需要安装gcc、..._clion centos
文章浏览阅读1.3k次,点赞18次,收藏21次。1.Qt 的可执行文件目录,通常是 /usr/local/Qt-5.15.2/bin,其中 5.15.2 是你安装的 Qt 版本号。链接:https://pan.baidu.com/s/1at9aW5-Q-wBNIIk5wRLM6A?3.Qt 的插件目录,通常是 /usr/local/Qt-5.15.2/plugins。2.Qt 的库文件目录,通常是 /usr/local/Qt-5.15.2/lib。_jetson编译安装qt
文章浏览阅读1.7k次,点赞2次,收藏9次。北理工-2021年春-《数字逻辑》实验_北京工业大学数字逻辑实验数字秒表设计
文章浏览阅读1.4k次,点赞19次,收藏15次。我们学习一门语言,或外语或编程语言,是不是都是要先学语法,想想这些语言有哪些相同点1、中文、英语、日语......是不是都有 主谓宾 的规则2、c、java、python、js......是不是都有 数据类型 、循环 等语法或数据结构虽然人们在过去的几十年里发明了多种编程语言,但基本的语言模式并不多。因为他们在设计时都会情不自禁的与自己脑海中的自然语言关联,并用数学符号表达了出来。因此如果你掌握了一门语言后再去学其他语言就会变的容易。
文章浏览阅读5.2w次,点赞27次,收藏102次。摘要:本文主要说明了如何在Windows安装运行Kafka_kafak windows版
文章浏览阅读4.3k次,点赞2次,收藏11次。element里面表格的一个属性 formatter 叫格式化内容的_formatter
文章浏览阅读897次。(MIT6.828) 1.实验环境搭建参考官网:https://pdos.csail.mit.edu/6.828/2018/tools.html在ubuntu14中安装x86模拟器QEMU.1. 检查工具链objdump -i会看到elf32-i386等信息gcc -m32 -print-libgcc-file-name会看到/usr/lib/gcc/i486-linux-gnu..._mit6.828实验是否能在虚拟机上完成
文章浏览阅读115次。原标题:官宣:MSVC新加入C11和C17标准官宣我们很高兴的宣布,从Visual Studio 2019 v16.8 Preview 3开始,C11和C17这两个C语言版本将加入到MSVC编译器工具集(toolset)。多年以来,Visual Studio仅仅是因为C++的需要才对C进行有限度的支持。现在,事情有转变了:我们在编译器中添加了一个基于token的规范化预处理器,借助于两项新加入的编..._msvc vla
文章浏览阅读563次,点赞8次,收藏9次。修改打包方式排除内置tomcat,删除内置undertow容器新增maven插件,忽略打包web.xml二、修改配置文件1.config中心的配置文件无法扫描到, 所以需要将外面的配置文件全部迁移到application.yml和bootstrap.yml中代码如下(示例):三.项目启动入口改造启动类同级目录下新建类:四. 添加nacos配置提示:如果服务需要注册到nacos中的话, 使用外置tomcat可能无法注册, 需要添加以下配置:来源于另一篇博文_springboot 金蝶中间件
文章浏览阅读1.1w次,点赞54次,收藏275次。首发于知乎最近在做基于EtherCAT的项目,看了一些网上的博客,感觉写的都比较松散。虽然,自己也是才开始学习,希望能把这段时间学到的东西总结一下。1.EtherCAT简介EtherCAT是由德国BECKHOFF自动化公司于2003年提出的实时工业以太网技术。它具有高速和高数据有效率的特点,支持多种设备连接拓扑结构。其从站节点使用专用的控制芯片,主站使用标准的以太网控制器。Et..._ethercat demo