JJWT实现令牌Token

article/2025/11/9 15:57:16

登录实现方式

Session

详情:

https://www.cnblogs.com/andy-zhou/p/5360107.html

会话的概念

会话就好比打电话,一次通话可以理解为一次会话。我们登录一个网站,在一个网站上不同的页面浏览,最后退出这个网站,也是一个会话。一个网站对于不同的用户会展示出不同的页面信息,但是在HTTP协议中,客户端请求服务端是一种无状态的连接-每次请求都是独立的请求,服务器怎么分辨这些请求是哪个用户发出的请求呢?

如果不能分辨哪个用户发出的请求,就不知道该反馈哪个用户的信息回来,那试想我们登录网站之后,显示的都是别人的信息岂不乱套了。所以服务器需要知道发出请求的是谁,需要一个用户标识来保证会话的正常进行。

Session的概念

Session 是存放在服务器端的,类似于Session结构来存放用户数据,当浏览器 第一次发送请求时,服务器自动生成了一个Session和一个Session ID用来唯一标识这个Session,并将其通过响应发送到浏览器。当浏览器第二次发送请求,会将前一次服务器响应中的Session ID放在请求中一并发送到服务器上,服务器从请求中提取出Session ID,并和保存的所有Session ID进行对比,找到这个用户对应的Session。可以自己匹配到对应用户的session

由于Session存放在服务器端,所以随着时间的推移或者用户访问的增多,会给服务器增加负担。使用的时候要考虑下服务器的性能。

Cookie的概念

Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端会把Cookie保存起来。

由于Cookie是存放在客户端,是可见的,安全性就会很低。因此不建议将一些重要的信息放在cookie中。

使用

​ Session在用户第一次访问服务器的时候自动创建。需要注意只有访问JSP、Servlet等程序时才会创建Session,只访问HTML、IMAGE等静态资源并不会创建Session。如果尚未生成Session,也可以使用request.getSession(true)强制生成Session。

Session是用于单体应用的,JSP页面

Cookie cookie = new Cookie("time", "20080808"); // 新建Cookie
cookie.setSecure(true); // 设置安全属性
response.addCookie(cookie); // 输出到客户端@PostMapping("/login")public String login(HttpSession session, String username){session.setAttribute("user", username);return "页面";}@PostMapping("/update")public String update(HttpSession session, Model model, User user){// 可以自己匹配到对应用户的sessionString username = session.getAttribute("user");if(username!=null&&username.equals.(user.getUsername())){//说明用户有登陆int k = userService.update(user);if (k>0){// 获取用户信息user = userService.select(user.getUsername());model.addAttribute("user", user);return "成功页面";}}return "失败页面";}// HttpServletRequest可作为controller
HttpServletRequest request =((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
HttpSession session=request.getSession();//达到session对象

Token

获取到令牌后,每次请求资源访问时都需要带token回来验证合法性和是否有权限。token一般包含用户的信息和权限集。实现token的框架有Spring Security oAuth2、Apache Shrio、JWT。

jwt令牌

JSON Web Token(JWT)是一个非常轻巧的规范。这个规范允许我们使用JWT在用户和服务器之间传递安全可靠的信息。一个JWT实际上就是一个字符串,它由三部分组成,头部、载荷与签名。

说白了就是封装了用户的身份信息,给各个微服务识别用户身份。

JWT的构成

头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。这也可以被表示成一个JSON对象。

{"typ":"JWT","alg":"HS256"}

在头部指明了签名算法是HS256算法。 我们进行BASE64编码http://base64.xpcha.com/,编码后的字符串如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

小知识:Base64是一种基于64个可打印字符来表示二进制数据的表示方法。由于2的6次方等于64,所以每6个比特为一个单元,对应某个可打印字符。三个字节有24个比特,对应于4个Base64单元,即3个字节需要用4个可打印字符来表示。JDK 中提供了非常方便的 BASE64EncoderBASE64Decoder,用它们可以非常方便的完成基于 BASE64 的编码和解码

载荷内容(playload)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

(1)标准中注册的声明(建议但不强制使用)(参与令牌校验)

iss: jwt签发者
sub: 当前令牌的描述说明
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。

(2)公共的声明(不参与令牌校验)

公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

(3)私有的声明(不参与令牌校验)

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

这个指的就是自定义的claim。比如下面面结构举例中的admin和name都属于自定的claim。这些claim跟JWT标准规定的claim区别在于:JWT规定的claim,JWT的接收方在拿到JWT之后,都知道怎么对这些标准的claim进行验证(还不知道是否能够验证);而private claims不会验证,除非明确告诉接收方要对这些claim进行验证以及规则才行。

定义一个payload:

{"sub":"1234567890","name":"John Doe","admin":true}

然后将其进行base64加密,得到Jwt的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9
签证(signature)

jwt的第三部分是一个签证信息(效验数据是否被篡改),这个签证信息由三部分组成:

header (base64后的)

payload (base64后的)

secret(盐)

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式HS256进行加盐secret组合加密,然后就构成了jwt的第三部分。

TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。签证不能被破解。

JJWT创建令牌

JJWT是一个提供端到端的JWT创建和验证的Java库。永远免费和开源(Apache License,版本2.0),JJWT很容易使用和理解。它被设计成一个以建筑为中心的流畅界面,隐藏了它的大部分复杂性。

官方文档:

https://github.com/jwtk/jjwt

创建TOKEN

(1)依赖引入

<!--鉴权-->
<jjwt.version>0.9.0</jjwt.version>
<!--鉴权-->
<dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>${jjwt.version}</version>
</dependency>

(2)创建测试

/test/java下创建测试类,并设置测试方法。

有很多时候,我们并不希望签发的token是永久生效的,所以我们可以为token添加一个过期时间。

public class JwtTest {/***** 创建Jwt令牌*/@Testpublic void testCreateJwt(){JwtBuilder builder= Jwts.builder().setId("888")             //设置唯一编号.setIssuer("吴")         //颁发者.setSubject("小白")        //设置主题  可以是JSON数据.setIssuedAt(new Date())  //设置签发日期.setExpiration(new Date(System.currentTimeMills()+3600000))//令牌过期时间,这里1小时.signWith(SignatureAlgorithm.HS256,"itcast");//设置签名 使用HS256算法,并设置SecretKey(字符串)//自定义载荷Map<String,Object> userInfo = new HashMap<String,Object>();userInfo.put("company","**公司");userInfo.put("address","深圳");builder.addClaims(userInfo);//构建 并返回一个字符串String token = builder.compact()System.out.println(token);}
}

运行打印结果:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NjIwNjIyODd9.RBLpZ79USMplQyfJCZFD2muHV_KLks7M1ZsjTu6Aez4

再次运行,会发现每次运行的结果是不一样的,因为我们的载荷中包含了时间。

解析TOKEN

我们刚才已经创建了token ,在web应用中这个操作是由服务端进行然后发给客户端,客户端在下次向服务端发送请求时需要携带这个token(这就好像是拿着一张门票一样),那服务端接到这个token应该解析出token中的信息(例如用户id),根据这些信息查询数据库返回相应的结果。

/**** 解析Jwt令牌数据*/
@Test
public void testParseJwt(){String token="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NjIwNjIyODd9.RBLpZ79USMplQyfJCZFD2muHV_KLks7M1ZsjTu6Aez4";Claims claims = Jwts.parser().setSigningKey("itcast"). //盐parseClaimsJws(token). // 要解析的令牌对象getBody(); // 获取解密后的数据System.out.println(claims);System.out.println(claims.toStrig());
}

运行打印效果:

{jti=888, sub=小白, iat=1562062287}

试着将token或签名秘钥篡改一下,会发现运行时就会报错,所以解析token也就是验证token.

如果,令牌过期则报错如下:

在这里插入图片描述

当前时间超过过期时间,则会报错。

自定义claims

我们刚才的例子只是存储了id和subject两个信息,如果你想存储更多的信息(例如角色)可以定义自定义claims。

创建测试类,并设置测试方法:

创建token:

在这里插入图片描述

运行打印效果:

eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NjIwNjMyOTIsImFkZHJlc3MiOiLmt7HlnLPpu5Hpqazorq3nu4PokKXnqIvluo_lkZjkuK3lv4MiLCJuYW1lIjoi546L5LqUIiwiYWdlIjoyN30.ZSbHt5qrxz0F1Ma9rVHHAIy4jMCBGIHoNaaPQXxV_dk
/**** 解析Jwt令牌数据*/
@Test
public void testParseJwt(){String compactJwt="eyJhbGciOiJIUzI1NiJ9.eyJqdGkiOiI4ODgiLCJzdWIiOiLlsI_nmb0iLCJpYXQiOjE1NjIwNjMyOTIsImFkZHJlc3MiOiLmt7HlnLPpu5Hpqazorq3nu4PokKXnqIvluo_lkZjkuK3lv4MiLCJuYW1lIjoi546L5LqUIiwiYWdlIjoyN30.ZSbHt5qrxz0F1Ma9rVHHAIy4jMCBGIHoNaaPQXxV_dk";Claims claims = Jwts.parser().setSigningKey("itcast").parseClaimsJws(compactJwt).getBody();System.out.println(claims);
}

运行效果:

在这里插入图片描述

鉴权处理

思路分析

在这里插入图片描述

1.用户通过访问微服务网关调用微服务,同时携带头文件信息(令牌一般放请求头,或者cookie、参数)
2.在微服务网关这里进行拦截,拦截后获取用户要访问的路径
3.识别用户访问的路径是否需要登录,如果需要,识别用户的身份是否能访问该路径[这里可以基于数据库设计一套权限]
4.如果需要权限访问,用户已经登录,则放行
5.如果需要权限访问,且用户未登录,则提示用户需要登录
6.用户通过网关访问用户微服务,进行登录验证
7.验证通过后,用户微服务会颁发一个令牌给网关,网关会将用户信息封装到头文件中,并响应用户
8.用户下次访问,携带头文件中的令牌信息即可识别是否登录

用户登录签发TOKEN工具类

(1)生成令牌工具类

在commons或gateway微服务中创建类JwtUtil,主要辅助生成Jwt令牌信息,代码如下:

package com.changgou.commons.utils;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.Base64;
import java.util.Date;/*** Title:JJWT生成令牌工具类* Description:* @author WZQ* @version 1.0.0* @date 2020/3/10*/
public class JwtUtil {//默认有效期public static final Long JWT_TTL = 3600000L;// 60 * 60 *1000  一个小时//Jwt令牌信息public static final String JWT_KEY = "itcast";/*** 生成令牌* @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);//如果令牌有效期为null,则默认设置有效期1小时if (ttlMillis == null) {ttlMillis = JwtUtil.JWT_TTL;}//令牌过期时间设置long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);//生成秘钥SecretKey secretKey = generalKey();//封装Jwt令牌信息JwtBuilder builder = Jwts.builder().setId(id)                    //唯一的ID.setSubject(subject)          // 主题  可以是JSON数据.setIssuer("admin")          // 签发者.setIssuedAt(now)             // 签发时间.signWith(signatureAlgorithm, secretKey) // 签名算法以及密匙.setExpiration(expDate);      // 设置过期时间return builder.compact();}/*** 生成加密 secretKey* 盐base64加密成新的盐* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getEncoder().encode(JwtUtil.JWT_KEY.getBytes());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 jwt = JwtUtil.createJWT("weiyibiaoshi", "aaaaaa", null);System.out.println(jwt);try {Claims claims = JwtUtil.parseJWT(jwt);System.out.println(claims);} catch (Exception e) {e.printStackTrace();}}
}

在这里插入图片描述

//exp获取的是时间戳,解析出来是Date,过期时间

(2) 用户登录成功 则签发TOKEN,修改登录的方法:

如果报错,尝试在该微服务也导入jjwt的依赖

代码如下:

/**** 用户登录*/
@RequestMapping(value = "/login")
public ResponseResult login(String username,String password,HttpServletResponse response){//查询用户信息User user = userService.findById(username);if(user!=null && BCrypt.checkpw(password,user.getPassword())){//设置令牌信息Map<String,Object> info = new HashMap<String,Object>();info.put("role","USER");info.put("success","SUCCESS");info.put("username",username);//生成令牌,过期日数不设置,默认String token = JwtUtil.createJWT(UUID.randomUUID().toString(), JSON.toJSONString(info),null);//IdUtil.simpleUUID(),hutool工具UUID去-//令牌存入cookieCookie cookie = new Cookie("Authorization",token);cookie.setDomain("localhost");cookie.setPath("/");response.addCookie(cookie);//或者直接给前端处理,请求头return new ResponseResult(true,StatusCode.OK,"登录成功!",token);}return  new ResponseResult(false,StatusCode.LOGINERROR,"账号或者密码错误!");
}/*** token验证过期* @param tokenMap* @return*/@PostMapping("/token/verify")@ApiOperation(value = "token验证过期")public ResponseResult<String> tokenVerify(@RequestBody Map<String,String> tokenMap) throws Exception {if (!StringUtils.isEmpty(tokenMap.get("token"))){Claims claims = JwtUtil.parseJWT(tokenMap.get("token"));//获取的是时间戳,解析出来是Date,过期时间Date expiration = claims.getExpiration();if (expiration.before(new Date())){return new ResponseResult<String>(ResponseResult.CodeStatus.OK,"需要重新登录","1");}return new ResponseResult<String>(ResponseResult.CodeStatus.OK,"不需要重新登录","2");}return new ResponseResult<String>(ResponseResult.CodeStatus.FAIL,"token为空",null);}

自定义全局过滤器

结合微服务网关实现令牌授权

拷贝JwtUtil到gateway-web网关微服务中,最好把JwtUtil拷贝到微服务网关中,导入commons到网关中可能报错,含有大量依赖。

创建过滤器类,如图所示:

在这里插入图片描述

AuthorizeFilter代码如下:

import com.changgou.gateway.web.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** Title:全局过滤器类* Description:* @author WZQ* @version 1.0.0* @date 2020/3/10*/
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {//令牌头名字private static final String AUTHORIZE_TOKEN = "Authorization";/**** 全局过滤器* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取Request、Response对象ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//获取请求的URIString path = request.getURI().getPath();//1.获取头文件中的令牌信息String tokent = request.getHeaders().getFirst(AUTHORIZE_TOKEN);//2.如果头文件中没有,则从请求参数中获取if (StringUtils.isEmpty(tokent)) {tokent = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);}//3.都没有则从cookie中获取if (StringUtils.isEmpty(tokent)) {HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);if (cookie!=null){tokent = cookie.getValue();}}//如果全为空,没有令牌,则拦截if (StringUtils.isEmpty(tokent)) {//设置没有权限的状态码,401没有权限response.setStatusCode(HttpStatus.UNAUTHORIZED);//返回return response.setComplete();}//有令牌//解析令牌数据try {Claims claims = JwtUtil.parseJWT(tokent);} catch (Exception e) {e.printStackTrace();//解析失败,响应401错误,没有权限response.setStatusCode(HttpStatus.UNAUTHORIZED);//空数据return response.setComplete();}//放行return chain.filter(exchange);}/**** 过滤器执行顺序* @return*/@Overridepublic int getOrder() {return 0;}
}

配置过滤规则

修改网关系统的yml文件:

根据业务过滤对应的路径

          routes:- id: changgou_goods_routeuri: lb://goodspredicates:- Path=/api/album/**,/api/brand/**,/api/cache/**,/api/categoryBrand/**,/api/category/**,/api/para/**,/api/pref/**,/api/sku/**,/api/spec/**,/api/spu/**,/api/stockBack/**,/api/template/**filters:- StripPrefix=1- name: RequestRateLimiter #请求数限流 名字不能随便写 ,使用默认的facatoryargs:key-resolver: "#{@ipKeyResolver}"redis-rate-limiter.replenishRate: 1redis-rate-limiter.burstCapacity: 1#用户微服务- id: changgou_user_routeuri: lb://userpredicates:- Path=/api/user/**,/api/address/**,/api/areas/**,/api/cities/**,/api/provinces/**filters:- StripPrefix=1

参考官方手册:

https://cloud.spring.io/spring-cloud-gateway/spring-cloud-gateway.html#_stripprefix_gatewayfilter_factory

会话保持

用户每次请求的时候,我们都需要获取令牌数据,方法有多重,可以在每次提交的时候,将数据提交到头文件中,也可以将数据存储到Cookie中,每次从Cookie中校验数据,还可以每次将令牌数据以参数的方式提交到网关,这里面采用Cookie的方式比较容易实现。

可以获取用户ip放到token里面,每次登录校验ip,不同ip登录得去掉上一次的登录状态。

登录封装Cookie

修改user微服务,每次登录的时候,添加令牌信息到Cookie中,看情况添加,代码如下:

/**** 用户登录*/
@RequestMapping(value = "/login")
public ResponseResult login(String username,String password,HttpServletResponse response){//查询用户信息User user = userService.findById(username);if(user!=null && BCrypt.checkpw(password,user.getPassword())){//设置令牌信息Map<String,Object> info = new HashMap<String,Object>();info.put("role","USER");info.put("success","SUCCESS");info.put("username",username);//生成令牌String token = JwtUtil.createJWT(UUID.randomUUID().toString(), JSON.toJSONString(info),null);//令牌存入cookieCookie cookie = new Cookie("Authorization",token);cookie.setDomain("localhost");cookie.setPath("/");response.addCookie(cookie);//或者直接给前端处理,请求头return new ResponseResult(true,StatusCode.OK,"登录成功!",token);}return  new ResponseResult(false,StatusCode.LOGINERROR,"账号或者密码错误!");
}

过滤器获取令牌数据

每次在网关中通过过滤器获取Cookie中的令牌,然后对令牌数据进行解析,修改微服务网关gateway中的全局过滤器AuthorizeFilter,代码如下:

        //3.都没有则从cookie中获取if (StringUtils.isEmpty(tokent)) {HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);if (cookie!=null){tokent = cookie.getValue();hasToken = false;}}

登录后测试,可以识别用户身份,不登录无法识别。如下访问http://localhost:8001/api/user会携带令牌数据:

在这里插入图片描述

添加Header信息

我们还可以在Gateway的全局过滤器中添加请求头信息,例如可以将令牌信息添加到请求头中,在资源微服务中获取头信息,如下代码:

修改微服务网关中的AuthorizeFilter过滤器,在令牌信息校验那块将令牌加入到请求头中,如下代码:

        //是在请求头,则trueboolean hasToken = true;//1.获取头文件中的令牌信息String tokent = request.getHeaders().getFirst(AUTHORIZE_TOKEN);//2.如果头文件中没有,则从请求参数中获取if (StringUtils.isEmpty(tokent)) {tokent = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);hasToken = false;}//3.都没有则从cookie中获取if (StringUtils.isEmpty(tokent)) {HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);if (cookie!=null){tokent = cookie.getValue();hasToken = false;}}//不是从请求头中拿到的tokenif (!hasToken){//将令牌封装到头文件中,让其访问其他资源服务器request.mutate().header(AUTHORIZE_TOKEN,tokent);}

在user微服务的UserController的findAll方法中获取请求头测试,代码如下:

在这里插入图片描述

后台输出令牌数据如下:

在这里插入图片描述

网关过滤器全部代码

package com.changgou.gateway.web.filter;import com.changgou.gateway.web.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpCookie;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;/*** Title:全局过滤器类* Description:* @author WZQ* @version 1.0.0* @date 2020/3/10*/
@Component
public class AuthorizeFilter implements GlobalFilter, Ordered {//令牌头名字private static final String AUTHORIZE_TOKEN = "Authorization";/**** 全局过滤器* @param exchange* @param chain* @return*/@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {//获取Request、Response对象ServerHttpRequest request = exchange.getRequest();ServerHttpResponse response = exchange.getResponse();//获取请求的URIString path = request.getURI().getPath();//如果是登录,注册等请求,一律放行if(URLFilter.hasAuthorize(path)){//放行return chain.filter(exchange);}//不在头文件中,则在这里封装到头文件中,资源服务器才可以访问,如果结合spring security的话,//都是放在请求头boolean hasToken = true;//1.获取头文件中的令牌信息String tokent = request.getHeaders().getFirst(AUTHORIZE_TOKEN);//2.如果头文件中没有,则从请求参数中获取if (StringUtils.isEmpty(tokent)) {tokent = request.getQueryParams().getFirst(AUTHORIZE_TOKEN);hasToken = false;}//3.都没有则从cookie中获取if (StringUtils.isEmpty(tokent)) {HttpCookie cookie = request.getCookies().getFirst(AUTHORIZE_TOKEN);if (cookie!=null){tokent = cookie.getValue();hasToken = false;}}//如果全为空,没有令牌,则拦截if (StringUtils.isEmpty(tokent)) {//设置没有权限的状态码,401没有权限response.setStatusCode(HttpStatus.UNAUTHORIZED);//返回return response.setComplete();}//看情况,可能需要统一加上“bearer ”,cookie无法加//如果全为空,没有令牌,则拦截if (StringUtils.isEmpty(tokent)) {//设置没有权限的状态码,401没有权限response.setStatusCode(HttpStatus.UNAUTHORIZED);//返回return response.setComplete();}else{//有令牌//解析令牌数据//Claims claims = JwtUtil.parseJWT(tokent);//判断是否有前缀"bearer "if (!tokent.startsWith("bearer ") || !tokent.startsWith("Bearer ")){tokent = "bearer "+tokent;}}//请求头没有,添加进去if (!hasToken){//将令牌封装到头文件中,让其访问其他资源服务器request.mutate().header(AUTHORIZE_TOKEN,tokent);}//放行return chain.filter(exchange);}/**** 过滤器执行顺序* @return*/@Overridepublic int getOrder() {return 0;}
}

http://chatgpt.dhexx.cn/article/Ky54Wsm4.shtml

相关文章

3.JJWT

目录 1.JWT简介 2.JWT的结构 3.基于服务器的传统身份认证 4.基于token的身份认证 5. JWT的优势 6.Java中使用JJWT实现JWT 1.JWT简介 Json web token (JWT)&#xff0c; 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519)。该token被设计为紧凑且安全的…

JWT技术

JWT 一、 JWT 实现无状态 Web 服务 1、什么是有状态 有状态服务&#xff0c;即服务端需要记录每次会话的客户端信息&#xff0c;从而识别客户端身份&#xff0c;根据用户身份进行请求的处理&#xff0c;典型的设计如tomcat中的session。 例如登录&#xff1a;用户登录后&am…

token学习笔记(JWT、jjwt的使用及案例实现)

文章目录 1. 首先、了解什么是会话2. 会话跟踪的主要技术3. Token 令牌学习3.1 流程图3.2 token3.3 JWT(JSON web Tokens)Json web 令牌(规范)3.4 JWT结构3.5 JWT需要的依赖3.6 JWT的获取与验证流程3.7JWT的使用方式3.8 jjwt的使用&#xff08;创建JWT方式&#xff09;1. jjwt需…

JWT 进阶 -- JJWT

###jwt是什么? JWTs是JSON对象的编码表示。JSON对象由零或多个名称/值对组成&#xff0c;其中名称为字符串&#xff0c;值为任意JSON值。JWT有助于在clear(例如在URL中)发送这样的信息&#xff0c;可以被信任为不可读(即加密的)、不可修改的(即签名)和URL - safe(即Base64编码…

JWT详解和使用(jjwt)

JWT详解和使用 JWT是啥 JWT&#xff08;JSON Web Token&#xff09;是一个开放标准(RFC 7519)&#xff0c;它定义了一种紧凑的、自包含的方式&#xff0c;用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任&#xff0c;因为它是数字签名的。 下列场景中使用…

JJWT 实现JWT

1什么是JJWT JJWT 是一个提供端到端的 JWT 创建和验证的 Java 库。永远免费和开源 (Apache License&#xff0c;版本2.0)&#xff0c;JJWT 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面&#xff0c;隐藏了它的大部分复杂性。 2JJWT快速入门 2.1token的创建 2.1…

什么是JWT?

在HTTP接口调用的时候&#xff0c;服务端经常需要对调用方做认证&#xff0c;以保证安全性。一种常见的认证方式是使用JWT(Json Web Token)&#xff0c;采用这种方式时&#xff0c;经常在header传入一个authorization字段&#xff0c;值为对应的jwt_token&#xff0c;或者也有图…

JWT的学习和JJWT的使用

1.什么是JWT JWT&#xff08;JSON Web Token&#xff09;是一个开放的行业标准&#xff0c;它定义了一种简介的&#xff0c;自包含的协议格式&#xff0c;用于在通信双方传递json对象&#xff0c;传递的信息经过数字签名可以被验证和信任。JWT可以使用HMAC算法或者使用RSA的公…

JWT详解

本文从本人博客搬运&#xff0c;原文格式更加美观&#xff0c;可以移步原文阅读&#xff1a;JWT详解 JWT简介 1.什么是JWT 在介绍JWT之前&#xff0c;我们先来回顾一下利用token进行用户身份验证的流程&#xff1a; 客户端使用用户名和密码请求登录服务端收到请求&#xff…

JWT详解、JJWT使用、token 令牌

前言 在正式讲解JWT之前&#xff0c;我们先重温一下用户身份认证相关的一些概念&#xff1a; 有状态登录&#xff08;session认证&#xff09; 服务器当中记录每一次的登录信息&#xff0c;从而根据客户端发送的数据来判断登录过来的用户是否合法。 缺点&#xff1a; 每个用…

Java的JJWT实现JWT

1 什么是 JJWT JJWT 是一个提供端到端的 JWT 创建和验证的 Java 库。永远免费和开源 (Apache License&#xff0c;版本2.0)&#xff0c;JJWT 很容易使用和理解。它被设计成一个以建筑为中心的流畅界面&#xff0c;隐藏了它的大部分复杂性。 2 token 的创建 2.1 引入依赖 &l…

解决Red Hat虚拟机与主机网络不通

虚拟机版本&#xff1a;Red Hat Enterprise Linux 7 64 位 安装&#xff1a;自定义安装&#xff0c;带GUI的服务器&#xff0c;创建图形化界面 创建完毕后发现网络ping不通&#xff0c;经过查阅各种资料&#xff0c;在同事的帮助下终于解决。做一个记录。 1、VMware网络配置。…

虚拟机VMware和宿主机连接

文章目录 一、NAT连接1.查看宿主机IP地址2.设置VMnet8信息2.设置虚拟机模式3.设置虚拟网络4.设置虚拟机内系统IP&#xff08;Centos8.2为例&#xff09;4.1.图形化操作4.1.1DHCP4.1.2静态IP4.1.3 重启网卡&#xff08;修改网卡信息后&#xff09; 5.测试5.1.宿主机ping虚拟机5.…

VMware虚拟机三种网络连接模式详解

VMware虚拟机三种网络连接模式详解 Vmware提供了三种网络工作模式&#xff0c;分别是&#xff1a;&#xff08;1&#xff09;Bridged&#xff08;桥接模式&#xff09;&#xff1b;&#xff08;2&#xff09;NAT&#xff08;网络地址转换模式&#xff09;&#xff1b;&#xf…

虚拟机与主机之间通信

1.bridged(桥接方式&#xff0c;默认使用vmnet0虚拟网卡)&#xff1a; 选择这种模式&#xff0c;虚拟机等同于网络内的一台物理主机&#xff0c;可对手动设置IP&#xff0c;子网掩码。DNS&#xff0c;且IP地址要和主机的IP在同一网段内。这样。虚拟机就和主机如同连在一个HUB上…

虚拟机的几种网络连接方式

系列运维 文章目录 系列运维前言一、几种网络连接方式各是什么&#xff1f;二、网络连接的差异性总结 前言 VirtualBox中有4种网络连接方式&#xff1a; NAT Bridged Adapter Internal Host-only Adapter VMWare中有三种&#xff0c;VirtualBox只是比VMWare多了Internal方式。…

主机、虚拟机、开发板之间网络连接设置

最近在玩开发板&#xff0c;主机使用的无线网卡&#xff0c;开发板与主机网线直连&#xff0c;现在开发板想使用tftp直接从虚拟机下载镜像等文件&#xff0c;偶尔又需要虚拟机从主机下载文件&#xff0c;虚拟机有时候又需要网络&#xff0c;经过一番折腾算是调试成功。 1.主机…

vmware虚拟机与主机共享网络

我的虚拟机总是各种连不上网&#xff0c;每次都要折腾一番。现在我把虚拟机连不上网的原因总体排查一下&#xff0c;按照流程一步步来&#xff0c;基本上可以解决大部分人的问题。 首先&#xff0c;在VMware的编辑->虚拟网络编辑器重新建立&#xff2e;&#xff21;&#xf…

Virtualbox虚拟机与主机相互访问

刚从vmware切换到Virtualbox有些地方还是不太熟悉。网络连接这块就被卡了一下&#xff0c;后来发现其实很简单&#xff0c;是我想多了。 环境 主机&#xff1a; archlinux 虚拟机&#xff1a;windows 10 软件版本&#xff1a;VirtualBox 6.1 理论上这些环境不影响&#xff0…

虚拟机和主机无法连接

vm网络配置&#xff1a;https://www.cnblogs.com/aeolian/p/8882790.html 一、首先查看自己的虚拟机服务有没有开启&#xff0c;选择电脑里面的服务查看&#xff1b; 1.计算机点击右键选择管理 2.进入管理选择VM开头的服务如果没有开启的话就右键开启 二、虚拟机服务开启后就…