「java中jwt」java中jwt框架

博主:adminadmin 2022-12-13 20:18:10 70

本篇文章给大家谈谈java中jwt,以及java中jwt框架对应的知识点,希望对各位有所帮助,不要忘了收藏本站喔。

本文目录一览:

怎样能让jwt在java与.net之间产生互通

public class Random1{

public static void main(String args[]) {

int a[] = new int[10];

for (int i = 0; i = 5; i++) {

a[i] = (int) (Math.random() * 10);//这个地方不能写成(int)Math.random()这是最大的错误

//其他地方乱七八糟的,我就自己写了

}

for (int i = 0; i 5;)

System.out.println(i + " : " + a[i++]);//代码中最好不要出现中文

}

}

JWT token封装以及自动刷新方案建议

什么是JWT

pom.xml

JWTUtil.java

用户登录操作

在前后分离场景下,越来越多的项目使用jwt token作为接口的安全机制,但存在jwt过期后,用户无法直接感知,假如在用户操作页面期间,突然提示登录,则体验很不友好,所以就有了token自动刷新需求;

方案:前端控制检测token,无感知刷新

用户登录成功的时候,一次性给他两个Token,分别为AccessToken和RefreshToken

AccessToken有效期较短,比如1天或者5天,用于正常请求

RefreshToken有效期可以设置长一些,例如10天、20天,作为刷新AccessToken的凭证

刷新方案:当AccessToken即将过期的时候,例如提前30分钟,客户端利用RefreshToken请求指定的API获取新的AccessToken并更新本地存储中的AccessToken

核心逻辑

1、登录成功后,jwt生成AccessToken; UUID生成RefreshToken并存储在服务端redis中,设置过期时间

2、接口返回3个字段AccessToken/RefreshToken/访问令牌过期时间戳

3、由于RefreshToken存储在服务端redis中,假如这个RefreshToken也过期,则提示重新登录;

老王的疑问:RefreshToken有效期那么长,和直接将AccessToken的有效期延长有什么区别

答:RefreshToken不像AccessToken那样在大多数请求中都被使用,主要是本地检测accessToken快过期的时候才使用,

一般本地存储的时候,也不叫refreshToken,前端可以取个别名,混淆代码让攻击者不能直接识别这个就是刷新令牌

缺点:前端每次请求需要判断token距离过期时间

优点:后端压力小,代码逻辑改动不大

刷新token方法未实现。

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

java jwt token 生成很慢啊

jwt不算慢,基本是毫秒,你测试的方法估计有问题,单元测试1次jwt生成基本都是1~2秒,因为java程序刚刚启动占用大量资源,你循环1000次jwt生成速度对比就知道了, 基本是毫秒级别!

如何在Java 中创建和验证JWT

用户发起登录请求,服务端创建一个加密后的jwt信息,作为token返回值,在后续请求中jwt信息作为请求头,服务端正确解密后可获取到存储的用户信息,表示验证通过;解密失败说明token无效或者已过期。

加密后jwt信息如下所示,是由.分割的三部分组成,分别为Header、Payload、Signature。

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiJqd3QiLCJpYXQiOjE0NzEyNzYyNTEsInN1YiI6IntcInVzZXJJZFwiOjEsXCJyb2xlSWRcIjoxfSIsImV4cCI6MTQ3MTMxOTQ1MX0.vW-pPSl5bU4dmORMa7UzPjBR0F6sqg3n3hQuKY8j35o

Header包含两部分信息,alg指加密类型,可选值为HS256、RSA等等,typ=JWT为固定值,表示token的类型。

{

"alg": "HS256",

"typ": "JWT"

}

Payload是指签名信息以及内容,一般包括iss (发行者), exp (过期时间), sub(用户信息), aud (接收者),以及其他信息,详细介绍请参考官网。

{

"sub": "1234567890",

"name": "John Doe",

"admin": true

}

Signature则为对Header、Payload的签名。

HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

在jwt官网,可以看到有不同语言的实现版本,这里使用的是Java版的jjwt。话不多说,直接看代码,加解密都很简单:

/**

* 创建 jwt

* @param id

* @param subject

* @param ttlMillis

* @return

* @throws Exception

*/

public String createJWT(String id, String subject, long ttlMillis) throws Exception {

SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256 ;

long nowMillis = System. currentTimeMillis();

Date now = new Date( nowMillis);

SecretKey key = generalKey();

JwtBuilder builder = Jwts. builder()

.setId(id)

.setIssuedAt(now)

.setSubject(subject)

.signWith(signatureAlgorithm, key);

if (ttlMillis = 0){

long expMillis = nowMillis + ttlMillis;

Date exp = new Date( expMillis);

builder.setExpiration( exp);

}

return builder.compact();

}

/**

* 解密 jwt

* @param jwt

* @return

* @throws Exception

*/

public Claims parseJWT(String jwt) throws Exception{

SecretKey key = generalKey();

Claims claims = Jwts. parser()

.setSigningKey( key)

.parseClaimsJws( jwt).getBody();

return claims;

}

加解密的key是通过固定字符串转换而生成的;subject为用户信息的json字符串;ttlMillis是指token的有效期,时间较短,需要定时更新。

这里要介绍的token刷新方式,是在生成token的同时生成一个有效期较长的refreshToken,后续由客户端定时根据refreshToken来获取最新的token。浏览器与服务端之间建立sse(server send event)请求,来实现刷新。关于sse在前面博文中有介绍过,此处略过不提。

JWT的TOKEN续期功能

JWT里有一个关键的东东,就是续期TOKEN,即TOKEN快过期时,刷新一个新的TOKEN给客户端.

办法如下:

1.后端生成TOKEN

importcom.starmark.core.shiro.model.SecurityUser;importcom.starmark.core.shiro.model.UserLoginToken;importcom.starmark.core.shiro.util.JWTUtil;importorg.apache.commons.lang3.BooleanUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.shiro.authc.AuthenticationException;importorg.apache.shiro.authc.AuthenticationToken;importorg.apache.shiro.subject.Subject;importorg.apache.shiro.web.filter.authc.AuthenticatingFilter;importorg.apache.shiro.web.util.WebUtils;importorg.slf4j.Logger;importorg.slf4j.LoggerFactory;importorg.springframework.web.bind.annotation.RequestMethod;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;importjavax.servlet.http.HttpServletRequest;importjavax.servlet.http.HttpServletResponse;importjava.time.LocalDateTime;importjava.time.ZoneId;importjava.util.Date;importjava.util.Objects;publicclassJwtAuthFilterextendsAuthenticatingFilter{privatefinalLoggerlog=LoggerFactory.getLogger(JwtAuthFilter.class);//10分钟后刷新tokenprivatestaticfinalinttokenRefreshInterval=60*10;@OverrideprotectedbooleanpreHandle(ServletRequestrequest,ServletResponseresponse)throwsException{HttpServletRequesthttpServletRequest=WebUtils.toHttp(request);if(httpServletRequest.getMethod().equals(RequestMethod.OPTIONS.name()))//对于OPTION请求做拦截,不做token校验returnfalse;returnsuper.preHandle(request,response);}@OverrideprotectedvoidpostHandle(ServletRequestrequest,ServletResponseresponse){request.setAttribute("jwtShiroFilter.FILTERED",true);}@OverrideprotectedbooleanisAccessAllowed(ServletRequestrequest,ServletResponseresponse,ObjectmappedValue){if(this.isLoginRequest(request,response)){returntrue;}BooleanafterFiltered=(Boolean)(request.getAttribute("jwtShiroFilter.FILTERED"));if(BooleanUtils.isTrue(afterFiltered))returntrue;booleanallowed=false;try{allowed=executeLogin(request,response);}catch(IllegalStateExceptione){//not found any tokenlog.error("Not found any token");}catch(Exceptione){log.error("Error occurs when login",e);}returnallowed||super.isPermissive(mappedValue);}@OverrideprotectedAuthenticationTokencreateToken(ServletRequestservletRequest,ServletResponseservletResponse){StringjwtToken=getAuthzHeader(servletRequest);if(StringUtils.isNotBlank(jwtToken)!JWTUtil.isTokenExpired(jwtToken))returnUserLoginToken.buildPassword(jwtToken,null,"jwt");returnnull;}@OverrideprotectedbooleanonAccessDenied(ServletRequestservletRequest,ServletResponseservletResponse)throwsException{HttpServletResponsehttpResponse=WebUtils.toHttp(servletResponse);httpResponse.sendRedirect("/unauth");returnfalse;}@OverrideprotectedbooleanonLoginSuccess(AuthenticationTokentoken,Subjectsubject,ServletRequestrequest,ServletResponseresponse){HttpServletResponsehttpResponse=WebUtils.toHttp(response);if(tokeninstanceofUserLoginToken"jwt".equalsIgnoreCase(((UserLoginToken)token).getLoginType())){UserLoginTokenjwtToken=(UserLoginToken)token;booleanshouldRefresh=shouldTokenRefresh(Objects.requireNonNull(JWTUtil.getIssuedAt(jwtToken.getUsername())));if(shouldRefresh){//生成新的TOKENSecurityUseruser=(SecurityUser)subject.getPrincipal();StringnewToken=JWTUtil.sign(user.getUserInfo().getId());httpResponse.setHeader("x-auth-token",newToken);}}returntrue;}@OverrideprotectedbooleanonLoginFailure(AuthenticationTokentoken,AuthenticationExceptione,ServletRequestrequest,ServletResponseresponse){log.error("Validate token fail, token:{}, error:{}",token.toString(),e.getMessage());returnfalse;}/**

    * 获取TOKEN

    * @param request 请求

    * @return token

    */privateStringgetAuthzHeader(ServletRequestrequest){HttpServletRequesthttpRequest=WebUtils.toHttp(request);Stringheader=httpRequest.getHeader("x-auth-token");returnStringUtils.removeStart(header,"Bearer ");}/**

    * 判断是否需要刷新TOKEN

    * @param issueAt token签发日期

    * @return 是否需要刷新TOKEN

    */privatebooleanshouldTokenRefresh(DateissueAt){LocalDateTimeissueTime=LocalDateTime.ofInstant(issueAt.toInstant(),ZoneId.systemDefault());returnLocalDateTime.now().minusSeconds(tokenRefreshInterval).isAfter(issueTime);}}

原签发TOKEN后10分钟后刷新新的TOKEN

2.前端获取TOKEN

// 拦截响应response,并做一些错误处理axios.interceptors.response.use((response)={if(response.status===200response.dataresponse.data.code===401){//console.log(window.location.origin);window.location.href=window.location.origin+window.location.pathname+'#/login';}//获取返回的TOKENconsttoken=response.headers['x-auth-token'];if(token){//将续期的TOKEN存起来localStorage.setItem("token",token);}// 这里是填写处理信息returnresponse;},(err)={// 这里是返回状态码不为200时候的错误处理console.log(err);if(errerr.response){switch(err.response.data.code){case400:err.message='请求错误';break;case401:err.message='未授权,请登录';break;case403:err.message='无权限';break;case404:err.message=`请求地址出错: ${err.response.config.url}`;break;case408:err.message='请求超时';break;case500:err.message='服务器内部错误';break;case501:err.message='服务未实现';break;case502:err.message='网关错误';break;case503:err.message='服务不可用';break;case504:err.message='网关超时';break;case505:err.message='HTTP版本不受支持';break;default:}}Vue.prototype.$message.error(err.response.data.msg!=null?err.response.data.msg:err.message);returnPromise.reject(err)});

注意一点,需要通过过滤器调整FITLER,增加Access-Control-Expose-Headers的输出,否则无法获取response中的header.

至此,JWT的TOKEN续期功能完成.

关于java中jwt和java中jwt框架的介绍到此就结束了,不知道你从中找到你需要的信息了吗 ?如果你还想了解更多这方面的信息,记得收藏关注本站。

The End

发布于:2022-12-13,除非注明,否则均为首码项目网原创文章,转载请注明出处。