做一个网站成本大概多少钱,有免费制作单页的网站吗,网站架构分析,常州百度seo什么是JWT#xff1f;
JWT#xff0c;通过数字签名的方式#xff0c;以json对象为载体#xff0c;在不同的服务终端之间安全的传输信息#xff0c;用来解决传统session的弊端。
JWT在前后端分离系统#xff0c;通过JSON形式作为WEB应用中的令牌(token)#xff0c;用于…什么是JWT
JWT通过数字签名的方式以json对象为载体在不同的服务终端之间安全的传输信息用来解决传统session的弊端。
JWT在前后端分离系统通过JSON形式作为WEB应用中的令牌(token)用于在各方之间安全地将信息作为JSON对象传输。在数据传输过程中还可以完成数据加密、签名等相关处理。
JWT能做什么?
1.授权一旦用户登录每个后续请求将包括JWT从而允许用户访问该令牌允许的路由服务和资源。单点登录是当今广泛使用JWT的一项功能因为它的开销很小并且可以在不同的域中轻松使用。
2.信息交换jwt是在各方之间安全地传输信息的好方法因为可以对JWT进行签名所以可以确保发件人是他们所说的人此外可以验证内容是否遭到篡改。
为什么会有JWT
传统的session认证有如下的问题
1.每个用户经过我们的应用认证之后将认证信息保存在session中由于session服务器中对象随着认证用户的增多服务器内存开销会明显增大
2.用户认证之后服务端使用session保存认证信息那么要取到认证信息只能访问同一台服务器才能拿到授权的资源。这样在分布式应用上就需要实现session共享机制不方便集群应用;
3.因为session是基于cookie来进行用户识别的cookie如果被截获用户就会很容易受到跨站请求伪造的攻击。
基于JWT的认证流程 前端通过web表单将自己的用户和密码发送到后端接口(一般是http-post请求建议使用SSL加密传输(https协议)以免敏感信息被嗅探)
后端核对用户名和密码成功后将用户的Id等其他信息作为JWT Payload(负载)将其与头部分别进行BASE64编码拼接后签名形成一个JWT(Token)形成的JWT就是一个字符(head.payload.singueater)后端将JWT字符串作为登录成功的结果返回给前端。前端结果保存在localStorage(本地缓存)或sessionStorage上退出登录时前端删除保存的JWT即可。前端在每次请求时将JWT放入http header中的Authorization位(解决XSS和XSRF问题)后端检查是否存在如存在验证JWT的有效性例如检查签名是否正确检查token是否过期检查token的接收方是否是自己(可选)。
JWT的优势
简洁可以通过URL、POST参数或Http header发送因为数据量小传输速度快自包含负载(属于JWT的一部分)中包含了用户所需要的信息不需要在服务器端保存会话信息不占服务器内存也避免了多次查询数据库特别适用于分布式微服务因为token是以json加密的形式保存在客户端的所以JWT可以跨语言使用原则上任何WEB形式都支持。不需要再服务端保存会话信息特别适用于分布式微服务。
JWT结构
JWT其实就是一段字符串由标头(Header)、有效载荷(Payload)和签名(Signature)这三部分组成用 . 拼接。在传输的时候会将JWT的三部分分别进行Base64编码后用 . 进行连接形成最终传输的字符串。
头部Header: JWT的头部是一个JSON对象用于描述JWT的元数据例如令牌的类型typ和签名算法alg。通常情况下头部会包含以下信息
{alg: HS256,typ: JWT
} - alg指定签名算法常见的有HMAC SHA256HS256和RSA SHA256RS256等。 - typ指定令牌的类型一般为JWT。 头部需要经过Base64编码后作为JWT的第一部分。 载荷Payload:JWT的载荷是存储实际数据的部分也是一个JSON对象。它包含了一些声明claims用于描述令牌的信息。常见的声明有:
{sub: 1234567890,name: John Doe,admin: true
} 前面两部分都使用Base64进行编码前端可以解开知道里面的信息 Signature需要使用编码后的header和payload以及我们提供的一密钥然后使用header中指定的签名算法进行签名以保证JWT没有被篡改过。 使用Signature签名可以防止内容被篡改。如果有人对头部及负载内容解码后进行修改再进行编码最后加上之前签名组成新的JWT。那么服务器会判断出新的头部和负载形成的签名和JWT附带的签名是不一样的。如果要对新的头部和负载进行签名在不知道服务器加密时用的密钥的话得出来的签名也是不一样的。 当用户希望访问一个受保护的路由或者资源的时候可以把它放在 Cookie 里面自动发送但是这样不能跨域所以更好的做法是放在 HTTP 请求头信息的 Authorization 字段里使用 Bearer 模式添加 JWT。 JWT测试demo
package com.qcby.springbootdemo1;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import org.junit.jupiter.api.Test;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;public class jwtTest {//JWT的生成Testpublic void testGen(){MapString,Object claims new HashMap();claims.put(id,1);claims.put(username,张三);String token JWT.create().withClaim(user,claims) //t添加第二部分.withExpiresAt(new Date(System.currentTimeMillis()1000*60*60*12)) //添加过期时间.sign(Algorithm.HMAC256(itheima));//指定算法,配置 密钥System.out.println(token);}//JWT的验证Testpublic void testGen1(){//定义字符串,模拟前端传过来的tokenString token eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyIjp7ImlkIjoxLCJ1c2VybmFtZSI6IuW8oOS4iSJ9LCJleHAiOjE3MzE2MjE4NjZ9.XKk_AiJ5njz7tXRG9xW5lWdrvq71LzIhiHKrvYsvvbI;//require:申请一个jwt的验证器JWTVerifier jwtVerifier JWT.require(Algorithm.HMAC256(itheima)).build();DecodedJWT decodedJWT jwtVerifier.verify(token);//验证token,生成一个解析后的JWT对象MapString, Claim claims decodedJWT.getClaims();System.out.println(claims.get(user));//拿到token中的信息//如果篡改了头部和载荷部分的数据,那么验证失败//如果密钥改了,验证失败//token过期}
}
封装的JwtUtil
package com.qcby.gaokao.util;
/*** JWT工具类*/
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.*;public class JwtUtil {//有效期为public static final Long JWT_TTL 60 * 60 *1000L;// 60 * 60 * 1000//设置秘钥明文public static final String JWT_KEY qcby;/*** 创建token* param id* param subject* param ttlMillis* return*/public static String createJWT(String id, String subject, Long ttlMillis) {//设置签名算法SignatureAlgorithm signatureAlgorithm SignatureAlgorithm.HS256;//获取当前时间为设置过期时间准备long nowMillis System.currentTimeMillis();Date now new Date(nowMillis);//如果调用方法时没有定义密钥就是JwtUtil中定义的if(ttlMillisnull){ttlMillisJwtUtil.JWT_TTL;}//设置过期时间long expMillis nowMillis ttlMillis;Date expDate new Date(expMillis);//设置加密后的密钥SecretKey secretKey generalKey();JwtBuilder builder Jwts.builder().setId(id) //唯一的ID.setSubject(subject) // 主题 可以是JSON数据.setIssuer(wd) // 签发者.setIssuedAt(now) // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);// 设置过期时间return builder.compact();}/*** 生成加密后的秘钥 secretKey* return*/public static SecretKey generalKey() {byte[] encodedKey Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key new SecretKeySpec(encodedKey, 0, encodedKey.length, AES);return key;}/*** 解析* param jwt* return* throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}public static void main(String[] args) {String token JwtUtil.createJWT(UUID.randomUUID().toString(),qd,null );System.out.println(token);}
}
在项目中的应用
我是在登录功能的时候使用的JWT技术
在我第一次登录的时候就会生成token令牌我的令牌的校验的功能在拦截器中进行了实现
登录部分
ListStudent students studentMapper.findone(student);
if(students.size() 1){//这些就是在进行登录拦截String token JwtUtil.createJWT(UUID.randomUUID().toString(),String.valueOf(students.get(0).getId()),null);//将token信息设置如cookie当中Cookie cookie new Cookie(token,token);cookie.setPath(/); //设置浏览器的访问路径cookie.setMaxAge(36000); //设置cookie的过期时间response.addCookie(cookie);/*** 下面是用于传递账户邮箱信息的功能*///1、获取该账户的邮箱String email students.get(0).getEmail();//2、将邮箱信息放入CookieCookie cookie1 new Cookie(email,email);cookie1.setPath(/);cookie1.setMaxAge(36000);response.addCookie(cookie1);//到此逻辑结束//登录成功return new ResponseResult(200,登录成功);}else {//登录失败return new ResponseResult(444,登录失败);}
拦截器部分
/*
* 配置拦截器
* */
Component
public class LoginInterceptor implements HandlerInterceptor {//拦截器Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {Cookie[] cookies request.getCookies();if(cookies ! null){for (Cookie cookie:cookies){if(token.equals(cookie.getName())){String userToken cookie.getValue();if(!StringUtils.hasText(userToken)){response.sendError(HttpServletResponse.SC_UNAUTHORIZED);}//解析token看看是否成功try {Claims claims JwtUtil.parseJWT(userToken);claims.getSubject();}catch (Exception e){//e.printStackTrace();System.out.println(token信息出错);return false;}return true; //放行}}}return false;}
}