javajwt(javajwt与jwk)
本篇文章给大家谈谈javajwt,以及javajwt与jwk对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。
本文目录一览:
- 1、Spring Security 整合 JSON Web Token(JWT)
- 2、java jwt如何刷新过期时间
- 3、SpringBoot整合JWT实现登录认证
- 4、jwt与token+redis,哪种方案更好用?
- 5、java jwt token 生成很慢啊
Spring Security 整合 JSON Web Token(JWT)
注:参考 Spring Security 整合 JSON Web Token(JWT) 提升 REST 安全性 ,写的特别全面,本文只是学习总结
基于token的鉴权机制
基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要搜返吵去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。
流程上是这样的:
1.用户使用用户名密码来请求服务器
2.服务器进行验证用户的信息
3.服务器通过验证发送给用户一个token
4.客户端存储token,并在每次请求时附送上这个token值
5.服务端验证token值,并返回数据
这个token必须要在每次请求时传递给服务端,它应该保存在请求头里, 另外,服务端要支持CORS(跨来源资源共享)策略,一般我们在服务端这么做就可以了世侍Access-Control-Allow-Origin: *。
第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).
jwt的头部承载两部分信息:
声明类型,这里是jwt
声明加密的算法 通常直接使用 HMAC SHA256
完整的头世敏部就像下面这样的JSON:
然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分.
载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分
1.标准中注册的声明
2.公共的声明
3.私有的声明
标准中注册的声明 (建议但不强制使用) :
iss : jwt签发者
sub : jwt所面向的用户
aud : 接收jwt的一方
exp : jwt的过期时间,这个过期时间必须要大于签发时间
nbf : 定义在什么时间之前,该jwt都是不可用的.
iat : jwt的签发时间
jti : jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共的声明 :
公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.
私有的声明 :
私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。
定义一个payload:
然后将其进行base64加密,得到Jwt的第二部分。
jwt的第三部分是一个签证信息,这个签证信息由三部分组成:
1.header (base64后的)
2.payload (base64后的)
3.secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。
将这三部分用.连接成一个完整的字符串,构成了最终的jwt:
注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。
如何应用
一般是在请求头里加入Authorization,并加上Bearer标注:
服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:
jwt-diagram
总结
优点
因为json的通用性,所以JWT是可以进行跨语言支持的,像JAVA,JavaScript,NodeJS,PHP等很多语言都可以使用。
因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息。
便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的。
它不需要在服务端保存会话信息, 所以它易于应用的扩展
安全相关
不应该在jwt的payload部分存放敏感信息,因为该部分是客户端可解密的部分。
保护好secret私钥,该私钥非常重要。
如果可以,请使用https协议
在SpringBoot中整合JWTSpring Security的步奏:
1.在项目中引入(本项目使用Gradle)
2.配置
目录结构如下:
WebSecurityConfig文件:
java jwt如何刷新过期时间
客户端
auth_header = JWT.encode({ user_id: 123, iat: Time.now.to_i, # 指定token发布时间 exp: Time.now.to_i + 2 # 指定token过期时间为2秒后,2秒时间足够一次HTTP请求,同时在一定程度确保上一次token过期,减少replay attack的概率运吵;}, "my shared secret")
RestClient.get("", authorization: auth_header)
服务端
class ApiController ActionController::Base
attr_reader :current_user
before_action :set_current_user_from_jwt_token
def set_current_user_from_jwt_token
# Step 1:解码JWT,并获取User ID,这个时候不对Token签名进行检查
# the signature. Note JWT tokens are *not* encrypted, but signed.
payload = JWT.decode(request.authorization, nil, false) # Step 2: 检查该用户是否存在于数据库
@current_user = User.find(payload['user_id'])
# Step 3: 检查Token签名是否正确.
JWT.decode(request.authorization, current_user.api_secret)
# Step 4: 检查握首 "iat" 和"exp" 以确保这个Token是在2秒旁皮侍内创建的.
now = Time.now.to_i if payload['iat'] now || payload['exp'] now # 如果过期则返回401
end
rescue JWT::DecodeError
# 返回 401
endend
[img]SpringBoot整合JWT实现登录认证
1、JWT的构成
- 头部(header):描述该JWT的最基本的信息,如类型以及签名所用的算法。
- 负载(payload):存放有效信息的地方。
- 签证(signature):base64加密后闹枝的header、base64加密后的payload和密钥secret加密后组成。
2、整合JWT
2.1 引入JWT依赖
com.auth0
java-jwt
3.18.3
2.2 编写漏好JWTUtils工具类
package com.stock.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import java.util.Calendar;
import java.util.Map;
public class JWTUtils {
private static final String SING="@#$%^*";
// 生成token
public static String getToken(Map map){
Calendar instance = Calendar.getInstance();
instance.add(Calendar.MINUTE,30);
//创建jwt builder
JWTCreator.Builder builder = JWT.create();
//payload
builder.withExpiresAt(instance.getTime());
map.forEach((k,v)-{
builder.withClaim(k,v);
});
//设置签名
String token = builder.sign(Algorithm.HMAC256(SING));
return token;
}
//验证令牌
public static void verifyToken(String token){
JWTVerifier require = JWT.require(Algorithm.HMAC256(SING)).build();
require.verify(token);
}
//获取token信息
public static DecodedJWT getTokenInfo(String token){
DecodedJWT verify = JWT.require(Algorithm.HMAC256(SING)).build().verify(token);
return verify;
}
}
2.3 编写拦截液搜敏器
public class JWTInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
System.out.println("OPTIONS请求,放行");
return true;
}
HashMap map = new HashMap();
String token = request.getHeader("token");
try {
JWTUtils.verifyToken(token);
return true;
}catch (SignatureVerificationException e){
map.put("msg","无效签名!");
}catch (TokenExpiredException e){
map.put("msg","token过期!");
}catch (AlgorithmMismatchException e){
map.put("msg","token加密算法不一致");
}catch (Exception e){
map.put("msg","无效签名!");
}
map.put("state",404);
map.put("path","/login");
//将map转化为字符串返回给前端
String result = new ObjectMapper().writeValueAsString(map);
response.setContentType("application/json;charset=UTF-8");
response.getWriter().println(result);
return false;
}
}
注意:
1、token存放在请求的header中;
2、在前后端分离的项目中,发送的GET/POST请求实则为两次请求。第一次请求为OPTIONS请求,第二次请求才是GET/POST请求;在OPTIONS请求中,不会携带请求头的参数,会导致在拦截器上获取请求头为空,自定义的拦截器拦截成功。第一次请求不能通过,就不能获取第二次的请求。所以需要在拦截器中加上如下代码来判断是否为OPTIONS请求,对于OPTIONS请求直接放过。
if (HttpMethod.OPTIONS.toString().equals(request.getMethod())) {
System.out.println("OPTIONS请求,放行");
return true;
}
2.4 配置拦截器
package com.stock.config;
import com.stock.Interceptors.JWTInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class IntercepterConfg implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new JWTInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login");
}
}
2.5 编写Controller
package com.stock.controller;
import com.stock.entity.User;
import com.stock.result.Result;
import com.stock.service.UserService;
import com.stock.utils.JWTUtils;
import com.stock.utils.ResultUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
@RestController
public class LoginController {
private UserService userService;
@Autowired
public LoginController(UserService userService) {
this.userService = userService;
}
@PostMapping("/login")
public Result register(User user){
HashMap map = new HashMap();
map.put("username",user.getUserName());
String token = JWTUtils.getToken(map);
HashMap data = new HashMap();
data.put("token",token);
return ResultUtils.getresult(200,"登录成功!",data);
}
@GetMapping("/main")
public Result tomain(){
return ResultUtils.getresult(200,"访问成功",null);
}
}
2.6使用Postman测试
- 未登录前访问127.0.0.1:8888/main
- 先登录再访问127.0.0.1:8888/main
jwt与token+redis,哪种方案更好用?
1.问题描述
jwt与token+redis,哪种方案更好用?
问题结论
刚好最近有项目使用了jwt,而且是定制化的jwt的认证机制,就个人的理解而言,各自有其优缺点,并且针对不同的场景需要进行约束性开发,如用户剔除、同一用户每2h只生成一次jwt等。
2.Token机制简述
2.1Token的用途
用户在登录APP时,APP端会发送加密的用户名和密码到服务器,服务器验证用户名和密码,如果验证成功,就会生成相应位数的字符产作为token存储到服务器中,并且磨隐将该token返回给APP端。以后APP再次请求时,凡是需要验证的地方都要带上该token,然后服务器端验证token,成功返回所需要的结果,失败返回错误信息,让用户重新登录。其中,服务器上会给token设置一个有效期,每次APP请求的时候都验证token和有效期。
在存储的时候把token进行对称加密存储,用到的时候再解密。文章最开始提到的签名sign:将请求URL、时间戳、token三者合并,通过算法进行加密处理。
2.2token+redis机制
用户验证通过后,服务端通过如uuid相关的方法,生成token,存储用户信息。当请求服务时,客户端将token带上激含来,进行查询验证,如token存在并在有限期内,请求有效,否则请求非法。
token+redis机制是中心化的,每次验证token有效性时,都需要访问redis,其核心优点实服务端可以主动让token失效,缺点是每次都要进行redis查询。占用redis存储空间。
2.3jwt机制
这是一种无状态身份验证机制,因为用户状态永远不会保存在服务器内存中。服务器受保护的路由将在授权头中检查有效的JWT,如果存在,则允许用户访问受保护的资源。由于JWT是独立的,所有必要的信息都在那里,减少了多次查询数据库的需求。
Javajwt普遍选用java-jwt工具包依赖,gradle依赖:compile'com.auth0:java-jwt:3.2.0'用户发起登录请求,验证通过后,服务端创建一个加密后的JWT信息,作为Token返回。在后续请求中JWT信息作为请求头,发给服务端。服务端拿到JWT之后进行解密,正确解密表示此次请求合法,验证通过;解密失败说明Token无效或者已过期。
jwt的有点主要有:a.其是去中心化的,便于分布式系统使用;2.基本信息可以直接放在token中。user_id,session_id;3.功能权限信息可以直接放在token中。用bit位表示用户所具有的功能权限。其缺点有:服务端无法主动让token失效,另一个是无法很好的控制payload的数据量。
3.小结
jwt和token+redis两种方案,没有最优,只有结合不同的业务场景,需求最适合的方案。就比如token2h过期,同一用户每1.5h只生成瞎铅厅一次token,当两次token并存时,同时有效。大家可以考虑在这两种方案的前提下,分别如何实现?
java jwt token 生成很慢啊
jwt不算慢,基本是毫秒,你测试的方法估计有问题,单元测试1次jwt生成基本都是1~2秒,因为java程序刚刚启动占用大量资源,你循环1000次jwt生成速颤李兄度对比就知道了, 基本茄袭是毫秒级扰含别!
关于javajwt和javajwt与jwk的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。