包含jwt实例java的词条

博主:adminadmin 2022-12-15 03:24:10 72

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

本文目录一览:

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

用户发起登录请求,服务端创建一个加密后的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在前面博文中有介绍过,此处略过不提。

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与Spring Security OAuth

通过 JWT 配合 Spring Security OAuth2 使用的方式,可以避免 每次请求 都 远程调度 认证授权服务。 资源服务器 只需要从 授权服务器 验证一次,返回 JWT。返回的 JWT 包含了 用户 的所有信息,包括 权限信息 。

1. 什么是JWT

JSON Web Token(JWT)是一种开放的标准(RFC 7519),JWT 定义了一种 紧凑 且 自包含 的标准,旨在将各个主体的信息包装为 JSON 对象。 主体信息 是通过 数字签名 进行 加密 和 验证 的。经常使用 HMAC 算法或 RSA( 公钥 / 私钥 的 非对称性加密 )算法对 JWT 进行签名, 安全性很高 。

2. JWT的结构

JWT 的结构由三部分组成:Header(头)、Payload(有效负荷)和 Signature(签名)。因此 JWT 通常的格式是 xxxxx.yyyyy.zzzzz。

2.1. Header

Header 通常是由 两部分 组成:令牌的 类型 (即 JWT)和使用的 算法类型 ,如 HMAC、SHA256 和 RSA。例如:

将 Header 用 Base64 编码作为 JWT 的 第一部分 ,不建议在 JWT 的 Header 中放置 敏感信息 。

2.2. Payload

下面是 Payload 部分的一个示例:

将 Payload 用 Base64 编码作为 JWT 的 第二部分 ,不建议在 JWT 的 Payload 中放置 敏感信息 。

2.3. Signature

要创建签名部分,需要利用 秘钥 对 Base64 编码后的 Header 和 Payload 进行 加密 ,加密算法的公式如下:

签名 可以用于验证 消息 在 传递过程 中有没有被更改。对于使用 私钥签名 的 token,它还可以验证 JWT 的 发送方 是否为它所称的 发送方 。

3. JWT的工作方式

客户端 获取 JWT 后,对于以后的 每次请求 ,都不需要再通过 授权服务 来判断该请求的 用户 以及该 用户的权限 。在微服务系统中,可以利用 JWT 实现 单点登录 。认证流程图如下:

4. 案例工程结构

工程原理示意图如下:

5. 构建auth-service授权服务

UserServiceDetail.java

UserRepository.java

实体类 User 和上一篇文章的内容一样,需要实现 UserDetails 接口,实体类 Role 需要实现 GrantedAuthority 接口。

User.java

Role.java

jks 文件的生成需要使用 Java keytool 工具,保证 Java 环境变量没问题,输入命令如下:

其中,-alias 选项为 别名 ,-keyalg 为 加密算法 ,-keypass 和 -storepass 为 密码选项 ,-keystore 为 jks 的 文件名称 ,-validity 为配置 jks 文件 过期时间 (单位:天)。

生成的 jks 文件作为 私钥 ,只允许 授权服务 所持有,用作 加密生成 JWT。把生成的 jks 文件放到 auth-service 模块的 src/main/resource 目录下即可。

对于 user-service 这样的 资源服务 ,需要使用 jks 的 公钥 对 JWT 进行 解密 。获取 jks 文件的 公钥 的命令如下:

这个命令要求安装 openSSL 下载地址,然后手动把安装的 openssl.exe 所在目录配置到 环境变量 。

输入密码 fzp123 后,显示的信息很多,只需要提取 PUBLIC KEY,即如下所示:

新建一个 public.cert 文件,将上面的 公钥信息 复制到 public.cert 文件中并保存。并将文件放到 user-service 等 资源服务 的 src/main/resources 目录下。至此 auth-service 搭建完毕。

maven 在项目编译时,可能会将 jks 文件 编译 ,导致 jks 文件 乱码 ,最后不可用。需要在 pom.xml 文件中添加以下内容:

6. 构建user-service资源服务

注入 JwtTokenStore 类型的 Bean,同时初始化 JWT 转换器 JwtAccessTokenConverter,设置用于解密 JWT 的 公钥 。

配置 资源服务 的认证管理,除了 注册 和 登录 的接口之外,其他的接口都需要 认证 。

新建一个配置类 GlobalMethodSecurityConfig,通过 @EnableGlobalMethodSecurity 注解开启 方法级别 的 安全验证 。

拷贝 auth-service 模块的 User、Role 和 UserRepository 三个类到本模块。在 Service 层的 UserService 编写一个 插入用户 的方法,代码如下:

配置用于用户密码 加密 的工具类 BPwdEncoderUtil:

实现一个 用户注册 的 API 接口 /user/register,代码如下:

在 Service 层的 UserServiceDetail 中添加一个 login() 方法,代码如下:

AuthServiceClient 作为 Feign Client,通过向 auth-service 服务接口 /oauth/token 远程调用获取 JWT。在请求 /oauth/token 的 API 接口中,需要在 请求头 传入 Authorization 信息, 认证类型 ( grant_type )、用户名 ( username ) 和 密码 ( password ),代码如下:

其中,AuthServiceHystrix 为 AuthServiceClient 的 熔断器 ,代码如下:

JWT 包含了 access_token、token_type 和 refresh_token 等信息,代码如下:

UserLoginDTO 包含了一个 User 和一个 JWT 成员属性,用于返回数据的实体:

登录异常类 UserLoginException

全局异常处理 切面类 ExceptionHandle

在 Web 层的 UserController 类中新增一个登录的 API 接口 /user/login 如下:

依次启动 eureka-service,auth-service 和 user-service 三个服务。

7. 使用Postman测试

因为没有权限,访问被拒绝。在数据库手动添加 ROLE_ADMIN 权限,并与该用户关联。重新登录并获取 JWT,再次请求 /user/foo 接口。

在本案例中,用户通过 登录接口 来获取 授权服务 加密后的 JWT。用户成功获取 JWT 后,在以后每次访问 资源服务 的请求中,都需要携带上 JWT。 资源服务 通过 公钥解密 JWT, 解密成功 后可以获取 用户信息 和 权限信息 ,从而判断该 JWT 所对应的 用户 是谁,具有什么 权限 。

获取一次 Token,多次使用, 资源服务 不再每次访问 授权服务 该 Token 所对应的 用户信息 和用户的 权限信息 。

一旦 用户信息 或者 权限信息 发生了改变,Token 中存储的相关信息并 没有改变 ,需要 重新登录 获取新的 Token。就算重新获取了 Token,如果原来的 Token 没有过期,仍然是可以使用的。一种改进方式是在登录成功后,将获取的 Token 缓存 在 网关上 。如果用户的 权限更改 ,将 网关 上缓存的 Token 删除 。当请求经过 网关 ,判断请求的 Token 在 缓存 中是否存在,如果缓存中不存在该 Token,则提示用户 重新登录 。

java jwt token 生成很慢啊

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

来,科普一下JWT

1. JSON Web Token是什么

JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

2. 什么时候你应该用JSON Web Tokens

下列场景中使用JSON Web Token是很有用的:

Authorization (授权) : 这是使用JWT的最常见场景。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。

Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。

3. JSON Web Token的结构是什么样的

JSON Web Token由三部分组成,它们之间用圆点(.)连接。这三部分分别是:

因此,一个典型的JWT看起来是这个样子的:

接下来,具体看一下每一部分:

Header

header典型的由两部分组成:token的类型(“JWT”)和算法名称(比如:HMAC SHA256或者RSA等等)。

例如:

然后,用Base64对这个JSON编码就得到JWT的第一部分

Payload

Public claims : 可以随意定义。

下面是一个例子:

对payload进行Base64编码就得到JWT的第二部分

Signature

为了得到签名部分,你必须有编码过的header、编码过的payload、一个秘钥,签名算法是header中指定的那个,然对它们签名即可。

例如:

签名是用于验证消息在传递过程中有没有被更改,并且,对于使用私钥签名的token,它还可以验证JWT的发送方是否为它所称的发送方。

看一张官网的图就明白了:

4. JSON Web Tokens是如何工作的

在认证的时候,当用户用他们的凭证成功登录以后,一个JSON Web Token将会被返回。此后,token就是用户凭证了,你必须非常小心以防止出现安全问题。一般而言,你保存令牌的时候不应该超过你所需要它的时间。

无论何时用户想要访问受保护的路由或者资源的时候,用户代理(通常是浏览器)都应该带上JWT,典型的,通常放在Authorization header中,用Bearer schema。

header应该看起来是这样的:

服务器上的受保护的路由将会检查Authorization header中的JWT是否有效,如果有效,则用户可以访问受保护的资源。如果JWT包含足够多的必需的数据,那么就可以减少对某些操作的数据库查询的需要,尽管可能并不总是如此。

如果token是在授权头(Authorization header)中发送的,那么跨源资源共享(CORS)将不会成为问题,因为它不使用cookie。

下面这张图显示了如何获取JWT以及使用它来访问APIs或者资源:

5. 基于Token的身份认证 与 基于服务器的身份认证

5.1. 基于服务器的身份认证

在讨论基于Token的身份认证是如何工作的以及它的好处之前,我们先来看一下以前我们是怎么做的:

HTTP协议是无状态的,也就是说,如果我们已经认证了一个用户,那么他下一次请求的时候,服务器不知道我是谁,我们必须再次认证

传统的做法是将已经认证过的用户信息存储在服务器上,比如Session。用户下次请求的时候带着Session ID,然后服务器以此检查用户是否认证过。

这种基于服务器的身份认证方式存在一些问题:

Sessions : 每次用户认证通过以后,服务器需要创建一条记录保存用户信息,通常是在内存中,随着认证通过的用户越来越多,服务器的在这里的开销就会越来越大。

Scalability : 由于Session是在内存中的,这就带来一些扩展性的问题。

CORS : 当我们想要扩展我们的应用,让我们的数据被多个移动设备使用时,我们必须考虑跨资源共享问题。当使用AJAX调用从另一个域名下获取资源时,我们可能会遇到禁止请求的问题。

CSRF : 用户很容易受到CSRF攻击。

5.2. JWT与Session的差异

相同点是,它们都是存储用户信息;然而,Session是在服务器端的,而JWT是在客户端的。

Session方式存储用户信息的最大问题在于要占用大量服务器内存,增加服务器的开销。

而JWT方式将用户状态分散到了客户端中,可以明显减轻服务端的内存压力。

Session的状态是存储在服务器端,客户端只有session id;而Token的状态是存储在客户端。

5.3. 基于Token的身份认证是如何工作的

基于Token的身份认证是无状态的,服务器或者Session中不会存储任何用户信息。

虽然这一实现可能会有所不同,但其主要流程如下:

注意:

5.4. 用Token的好处

无状态和可扩展性: Tokens存储在客户端。完全无状态,可扩展。我们的负载均衡器可以将用户传递到任意服务器,因为在任何地方都没有状态或会话信息。

安全: Token不是Cookie。(The token, not a cookie.)每次请求的时候Token都会被发送。而且,由于没有Cookie被发送,还有助于防止CSRF攻击。即使在你的实现中将token存储到客户端的Cookie中,这个Cookie也只是一种存储机制,而非身份认证机制。没有基于会话的信息可以操作,因为我们没有会话!

还有一点,token在一段时间以后会过期,这个时候用户需要重新登录。这有助于我们保持安全。还有一个概念叫token撤销,它允许我们根据相同的授权许可使特定的token甚至一组token无效。

5.5. JWT与OAuth的区别

写在最后:我为大家准备了一些适合于1-5年以上开发经验的java程序员面试涉及到的绝大部分面试题及答案做成了文档和学习笔记文件以及架构视频资料免费分享给大家(包括Dubbo、Redis、Netty、zookeeper、Spring cloud、分布式、高并发等架构技术资料),希望可以帮助到大家。

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

The End

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