技术标签: jwt SpringBoot
jwt官网:https://jwt.io/
如上是官网的介绍,这里我说一下大概的意思
JWT,拆分来理解就是JSON Web Token的意思,是一种开放标准。
它定义了一种紧凑并、包含的方式。
以JSON格式的形式在各方面安全的传输信息
因为它由数字签名,所以可以对其进行验证与信任
jwt可以使用秘密(使用HMAC算法)签名,也可以使用RSA或ECDSA公钥/私钥对签名
授权
这是使用JWT最常见的场景。一旦用户登录,每个后续请求将包括JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是目前JWT广泛使用的一个特性,因为它的开销很小,而且可以轻松地跨不同的领域使用。
信息交换
JSON Web令牌是在各方之间安全地传输信息的一种好方法。因为jwt可以签名(例如,使用公钥/私钥对),所以可以确定发送方就是他们所说的那个人。此外,由于使用头和有效负载计算签名,您还可以验证内容没有被篡改。
在紧凑的形式下,JSON Web令牌由三个由点(.)分隔的部分组成。
主要组成由
头
有效载荷
签名
报头通常由两部分组成:令牌的类型,即JWT,以及使用的签名算法,如HMAC SHA256或RSA。
{
"alg": "HS256",
"typ": "JWT"
}
然后,该JSON是Base64Url编码,以形成JWT的第一部分。
令牌的第二部分是有效负载,其中包含声明。声明是关于实体(通常是用户)和其他数据的语句。索赔有三种类型:注册索赔、公共索赔和私人索赔
要创建签名部分,您必须获取编码的头部、编码的有效载荷、一个秘密、头部中指定的算法,并对其进行签名。
例如,如果使用HMAC SHA256算法,将按照如下方式创建签名:
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
签名用于验证消息没有在此过程中被更改,并且,对于使用私钥签名的令牌,它还可以验证JwT的发送方是它所说的那个人。
在身份验证中,当用户使用其凭证成功登录时,将返回一个JSON Web令牌。由于令牌是凭据,必须非常小心地防止安全问题。一般来说,不应该将令牌保存的时间超过所需的时间。由于缺乏安全性,也不应该在浏览器存储中存储敏感的会话数据。
当用户希望访问受保护的路由或资源时,用户代理应该发送JWT,通常是在使用承载模式的授权头中。标题的内容应该如下所示:
Authorization: Bearer <token>
流程图
认证流程
1.访问者在web前端提供用户访问信息,接着根据确认按钮将信息返回给后端
api,提交的过程一般是(http/https)POST请求,建议使用通过SSL加密传输
协议(https post)方式提交,从而避免敏感信息被嗅探
后端将前端传输过来的信息核对正确后,将用户的信息作为jwt payload(负载)
将其与头部进行Base64编码后拼接签名,形成jwt,例子如下
lll.xxx.zzz
jwt使用拦截器将拦截相关地址,通过业务逻辑进入对应的数据展示,错误则返回至登录页面
前端每次请求将iwt放至http head中的authorization位,解决了xss与xsrf问题
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.0</version>
</dependency>
package com.uncletj.fujii.demo;
import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import sun.misc.Cleaner;
import java.util.Calendar;
import java.util.HashMap;
/**
* @Author Fujii Uncle
* @Date 2021-08-08 22:29
* @Version SpringBoot 2.2.2
* @projectName token的生成
*/
public class JwtDemo {
/**
* 密钥:可以随意声明
* 当然可以在方法内直接输入,但是我们使用变量声明更好找到去更改
*/
private static final String sign = "!@#QFHF15Q.*";
public static void main(String[] args) {
HashMap<String,Object> map = new HashMap<>();
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,20);
String jwt = JWT.create()
.withHeader(map)//header
.withClaim("username","Fujii Uncle")//payload
.withClaim("password","123456")
.withExpiresAt(instance.getTime())//指定过期时间
.sign(Algorithm.HMAC256(sign));//签名
//打印token
System.out.println("打印token:"+jwt);
}
}
执行结果
package com.uncletj.fujii.demo;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
/**
* @Author Fujii uncle
* @Date 2021-08-08 22:45
* @Version SpringBoot 2.2.2
* @projectName token验证
*/
public class VerifyDemo {
public static void main(String[] args) {
//创建验证对象
JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256("!@#QFHF15Q.*")).build();
DecodedJWT jwt = jwtVerifier.verify("eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXNzd29yZCI6IjEyMzQ1NiIsImV4cCI6MTYyODQzNDQ0NywidXNlcm5hbWUiOiJGdWppaSBVbmNsZSJ9.dUj-bMgoQvSNNaKxnzTxjL52mI83xNrN2kMLeT9mnSI");
//获取信息
System.out.println("用户名:"+jwt.getClaim("username").asString());
System.out.println("密码:"+jwt.getClaim("password").asString());
}
}
过期异常,需在设置的时间内进行验证,否则token过期后无法验证
获取信息成功如下
从上面的案例得知我们在使用jwt主要是生成令牌以及基于令牌的验证与解密,在我们的web项目中也是根据获取到用户信息之后去生成令牌,在用户拿到令牌之后呢在去做相应的解析,这里我将这两部操作封装成一个工具类
package com.uncletj.fujii.demo;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.Calendar;
import java.util.HashMap;
import java.util.Map;
/**
* @Date 2021/8/9 10:58
* @Version SpringBoot 2.2.2
* @packageName
*/
public class JwtUtils {
private static final String sign = "!@QW#E$S7<G";
/**
* 生成token header.payload.sgin
*
*/
public static String getToken(Map<String,String>user){
HashMap<String,Object> map = new HashMap<>();
Calendar instance = Calendar.getInstance();
instance.add(Calendar.SECOND,120);
//创建jwt builder
JWTCreator.Builder builder = JWT.create();
//payload
user.forEach((k,v)->{
builder.withClaim(k,v);
});
String token = JWT.create()
.withHeader(map)//头部
.withExpiresAt(instance.getTime()) //设置过期时间
.sign(Algorithm.HMAC256(sign));//签名
return token;
}
/**
* 验证token
*/
public static DecodedJWT verify(String token){
DecodedJWT jwt = JWT.require(Algorithm.HMAC256(sign)).build().verify(token);
return jwt;
}
}
依赖引入
<!--spring web 组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--mybatis plus 组件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1.tmp</version>
</dependency>
<!--mybatis plus代码生成器 组件-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.4.1</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.30</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!--spring boot 组件-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--mysql 组件-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--lombok 组件-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
server:
port: 8081
spring:
datasource:
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/testdb?useUnicode=true&useSSL=false&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: root
mybatis-plus:
mapper-locations: classpath:mapper/*.xml
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
---------------------------------user实体类----------------------------------
package com.uncletj.fujii.entity;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* @Date 2021/8/9 15:45
* @Version SpringBoot 2.2.2
* @packageName 用户实体类
*/
@Data
@TableName(value = "user")
@Accessors(chain = true)
public class User {
@TableId(value = "id",type = IdType.AUTO)
private long id;
private String username;
private String password;
}
----------------------------------------------------------------------------
---------------------------------user持久层----------------------------------
package com.uncletj.fujii.mapper;
import com.uncletj.fujii.entity.User;
import org.apache.ibatis.annotations.Mapper;
/**
* @Date 2021/8/9 15:47
* @Version SpringBoot 2.2.2
* @packageName 用户持久层
*/
@Mapper
public interface UserMapper {
User login(String username,String password);
}
xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.uncletj.fujii.mapper.UserMapper">
<select id="login" resultType="com.uncletj.fujii.entity.User">
select * from user where username=#{
username} and password=#{
password}
</select>
</mapper>
----------------------------------------------------------------------------
---------------------------------user业务层----------------------------------
service
package com.uncletj.fujii.service;
import com.uncletj.fujii.entity.User;
/**
* @Date 2021/8/9 15:51
* @Version SpringBoot 2.2.2
* @packageName 用户业务层
*/
public interface UserService {
User login(String username, String password);
}
serviceimpl
package com.uncletj.fujii.service.impl;
import com.uncletj.fujii.entity.User;
import com.uncletj.fujii.mapper.UserMapper;
import com.uncletj.fujii.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
/**
* @Date 2021/8/9 15:52
* @Version SpringBoot 2.2.2
* @packageName
*/
@Service
public class UserServiceImpl implements UserService {
@Resource
private UserMapper userMapper;
@Override
@Transactional(propagation = Propagation.SUPPORTS)
public User login(String username, String password) {
User user = userMapper.login(username,password);
if (user!=null){
return user;
}
throw new RuntimeException("用户名称或密码错误");
}
}
---------------------------------user控制层----------------------------------
package com.uncletj.fujii.controller;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.uncletj.fujii.entity.User;
import com.uncletj.fujii.service.UserService;
import com.uncletj.fujii.utils.JwtUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* @Date 2021/8/9 15:55
* @Version SpringBoot 2.2.2
* @packageName 用户控制层
*/
@RestController
@Slf4j
@RequestMapping("/user")
public class LoginController {
@Autowired
private UserService userService;
@PostMapping("/login")
public Map<String,Object> login(@RequestBody User user){
log.info("用户名:"+user.getUsername());
log.info("密码:"+user.getPassword());
Map<String,Object> map = new HashMap<>();
try {
User userdb = userService.login(user.getUsername(),user.getPassword());
//令牌生成
Map<String,String> payload = new HashMap<>();
payload.put("username",user.getUsername());
payload.put("password",user.getPassword());
String token = JwtUtils.getToken(payload);
map.put("status",true);
map.put("msg","认证成功");
map.put("token",token);//token响应
}catch (Exception e){
map.put("status",false);
map.put("msg","认证失败");
}
return map;
}
@GetMapping("/test")
public Map<String,Object> getToken(String token){
Map<String,Object> map = new HashMap<>();
map.put("status",true);
map.put("msg","请求成功");
return map;
}
}
----------------------------------------------------------------------------
---------------------------------user工具层----------------------------------
在如上工具层已展现
----------------------------------------------------------------------------
---------------------------------user拦截层----------------------------------
package com.uncletj.fujii.interceptors;
import com.auth0.jwt.exceptions.AlgorithmMismatchException;
import com.auth0.jwt.exceptions.SignatureVerificationException;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.uncletj.fujii.utils.JwtUtils;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.HashMap;
import java.util.Map;
/**
* @Date 2021/8/9 16:35
* @Version SpringBoot 2.2.2
* @packageName
*/
public class JWTInterceptors implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
Map<String,Object> map = new HashMap<>();
//获取请求头部令牌
String token = request.getHeader("token");
try {
//验证令牌
DecodedJWT decodedJWT = JwtUtils.verify(token);
return true;
}catch (SignatureVerificationException e){
e.printStackTrace();
map.put("msg","无效签名");
}catch (TokenExpiredException e){
e.printStackTrace();
map.put("msg","token过期!");
}catch (AlgorithmMismatchException e){
e.printStackTrace();
map.put("msg","token算法不一致!");
}catch (Exception e){
e.printStackTrace();
map.put("msg","token无效!");
}
map.put("state",false); //状态
//转json
String json = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=utf-8");
response.getWriter().println(json);
return false;
}
}
----------------------------------------------------------------------------
---------------------------------user配置层----------------------------------
package com.uncletj.fujii.config;
import com.uncletj.fujii.interceptors.JWTInterceptors;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @Date 2021/8/9 16:42
* @Version SpringBoot 2.2.2
* @packageName
*/
@Configuration
public class InteceptorsConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptors())
.addPathPatterns("/user/test") //需验证接口
.excludePathPatterns("/user/login");//放行接口
}
}
----------------------------------------------------------------------------
根据以上编码得出以下测试结果,测试工具使用postman
将用户登陆成功后的token放至header部,访问成功
结束语
若要前行,就要离开你现在停留的地方!
用 gmail 作为发送服务器。为了用git send-email通过gmail服务器发送patch。首先编辑 ~/.gitconfig , 写入你的账号配置[sendemail]smtpencryption = tlssmtpserver = smtp.gmail.comsmtpuser = [email protected] = 5
要知道什么是个性化推荐系统,那么就要先了解什么是推荐系统:什么是推荐系统推荐系统就是利用电子商务网站或APP向客户提供商品信息和建议,有意地引导用户的意向,帮助用户决定应该购买什么产品,模拟销售人员帮助客户完成整个购买过程。而个性化推荐系统是根据用户的兴趣特点和购买行为,向用户推荐用户感兴趣的信息和物品,使用户产生购买的意向。如果这些你对没有一个确切的概念,那么说购物网站上面每次所向你一些你..._大数据推荐系统
傅盛离职内情:从360叛将到腾讯马前卒投递人 itwriter发布于 2011-10-20 13:43评论(111)有14666人阅读原文链接 [收藏] « » 我是360的首席架构师李钊,傅盛的自述里谈到了我,涉及一些往事,我来说几句吧,关于傅盛、周鸿祎、雷军,还有马化腾之间那些不为人知的事情。 3Q大战的幕后总导演 先扯远点,抖个包袱吧。3Q
今天遇到一个奇怪的问题,一个节目中,设置了两个渠道启动计时器(Forms.Timer),其中一个渠道计时器正常工作,另一个渠道计时器不工作。//按钮btnBedIn绑定的事件private void bedIn(object sender, EventArgs e){ //... timerTotalTime.Start();}//在独立线程中调用(无效,tim..._主界面invoke执行会使forms.timer不计时
如何自学游戏引擎的开发
https://www.kubernetes.org.cn/2693.html转载于:https://www.cnblogs.com/elnino/p/10195878.html
思科统一计算系统概述思科统一计算系统是下一代数据中心平台,在一个紧密结合的系统中整合了计算、网络、存储接入与虚拟化功能,旨在降低总体拥有成本(TCO),同时提高业务灵活性。该系统包含一个低延时无丢包万兆以太网统一网络阵列,以及多台企业级x86架构服务器。它是一个集成的可扩展多机箱平台,在统一的管理域中管理所有资源。(图1)。图1. 思科统一计算系统是一个紧密结合的高可用性架构产品概述Cisco ...
NGUI如何使用TweenScale使物体大小回到初始状态gameObject.GetComponent().ResetToBeginning();_ngui tween resettobeginning
function merge(nums1, nums2) { var len1 = nums1.length - 1; var len2 = nums2.length - 1; var len = nums1.length + nums2.length - 1; while (len1 >= 0 && len2 >= 0) { nums1[l..._let nums =[3, 6, 9, 12, 15, 18, 21, …, 195, 198];查找72大的索引
在内网一台服务器上面操作,忽然敲打一个ll命令提示Input/output errorLs,pwd常用命令都报这个错;ssh -v [email protected]_7.4p1, OpenSSL 1.0.2k-fips 26 Jan 2017debug1: Reading configuration data /home/common/.ssh/conf..._ll 输入输出错误
安装openssl走了很多弯路,记录一下。1、下载原材料:openssl:https://www.openssl.org/source/vs2017:https://www.visualstudio.com/zh-hans/downloads/nasm:http://www.nasm.us/因为报错nasm not found,下了nasm,它是一个汇编语言编译程序。2、环境变量: 添加N_vs2017如何安裝openssl
一、设计目的目标1、通过PC机发送数据到STC板上2、通过按下K2或使振动传感器受到震动开始游戏3、通过导航按键上(下)键调大(小)数字,并显示在数码管上4、通过按下K1确认数据5、通过LED灯表示显示所猜数据与实际数据的大小关系6、当猜对时蜂鸣器播放一段音乐,代表可以把该价格的物品带回家7、在数码管最后一位显示所剩下的猜数机会,当3次都没猜对时,数码管跳零报错,按下K..._单片机如何计算不同商品组合的价格呢