jwt怎么获取当前登录用户_JWT实现登录认证

该博客详细介绍了如何使用JWT(JSON Web Tokens)进行登录认证,包括JWT的优势和不足,如紧凑轻量但无法吊销令牌。文章提供了一个完整的JWT登录流程,包括加密工具类、登录类和验证登录的过滤器。在登录验证后,会将用户ID存入header中供后续服务使用。
摘要由CSDN通过智能技术生成

登录流程

image

JWT优劣

优势

1.紧凑轻量

2.token自身包含用户信息且无法篡改,在服务(网关)中可以自行解析校验出用户信息,对认证服务器(account-svc)压力小

不足

1.无法吊销令牌,只能等待令牌自身过期

2.令牌长度与其包含用户信息多少正相关,传输开销较大

工具类

引入依赖

com.auth0

java-jwt

3.6.0

org.bouncycastle

bcprov-jdk15on

1.60

HmacSHA256加密类

import org.bouncycastle.util.encoders.Hex;

import javax.crypto.Mac;

import javax.crypto.spec.SecretKeySpec;

public class Hash {

/**

* HmacSHA256加密

*

* @param key 密钥

* @param data 数据

* @return 加密结果

*/

public static String encode(String key, String data) {

String code = null;

try {

Mac sha256_HMAC = Mac.getInstance("HmacSHA256");

SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");

sha256_HMAC.init(secret_key);

code = Hex.toHexString(sha256_HMAC.doFinal(data.getBytes("UTF-8")));

} catch (Exception e) {

throw new RuntimeException("密码编码错误");

}

return code;

}

}

获取request中数据的工具类

import org.springframework.http.HttpHeaders;

import org.springframework.http.server.reactive.ServerHttpRequest;

import org.springframework.web.server.ServerWebExchange;

import java.util.List;

import java.util.function.Consumer;

public class RequestDataExtractor {

/**

* 获取请求头

*/

public static String getHeader(ServerHttpRequest request, String key) {

List list = request.getHeaders().get(key);

if (list == null) {

return null;

}

return list.get(0);

}

/**

* 获得访问路径

*/

public static String getPath(ServerHttpRequest request) {

return request.getURI().getPath();

}

/**

* 添加请求头

*/

public static void addHeader(ServerWebExchange exchange, Consumer httpHeaders) {

ServerHttpRequest request = exchange.getRequest();

ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders).build();

exchange.mutate().request(serverHttpRequest).build();

}

}

登录类

import com.auth0.jwt.JWT;

import com.auth0.jwt.JWTVerifier;

import com.auth0.jwt.algorithms.Algorithm;

import com.auth0.jwt.interfaces.DecodedJWT;

import gnl.alibaba.common.dto.UserDto;

import gnl.alibaba.common.exception.ServiceException;

import org.springframework.util.StringUtils;

import java.util.Date;

import java.util.HashMap;

import java.util.Map;

public class Sign {

//token中包含的参数,可自行添加

public static final String CLAIM_USER_ID = "userId";

public static final String CLAIM_ACCOUNT = "account";

public static final String CLAIM_NAME = "name";

public static final String CLAIM_GENDER = "gender";

private static Map verifierMap = new HashMap();

private static Map algorithmMap = new HashMap();

/**

* 生成Token

*

* @param userDto 用户信息

* @param signingToken 密钥

* @param duration 过期时间

* @return token

*/

public static String generateSessionToken(UserDto userDto, String signingToken, long duration) {

if (StringUtils.isEmpty(signingToken)) {

throw new ServiceException("No signing token present");

}

Algorithm algorithm = getAlgorithm(signingToken);

String token = JWT.create()

.withClaim(CLAIM_USER_ID, userDto.getId())

.withClaim(CLAIM_ACCOUNT, userDto.getAccount())

.withClaim(CLAIM_NAME, userDto.getName())

.withClaim(CLAIM_GENDER, Integer.valueOf(userDto.getGender()))

.withExpiresAt(new Date(System.currentTimeMillis() + duration))

.sign(algorithm);

return token;

}

/**

* 校验token

*

* @param tokenString token

* @param signingToken 密钥

* @return

*/

public static DecodedJWT verifySessionToken(String tokenString, String signingToken) {

return verifyToken(tokenString, signingToken);

}

static DecodedJWT verifyToken(String tokenString, String signingToken) {

JWTVerifier verifier = verifierMap.get(signingToken);

if (verifier == null) {

synchronized (verifierMap) {

verifier = verifierMap.get(signingToken);

if (verifier == null) {

Algorithm algorithm = Algorithm.HMAC512(signingToken);

verifier = JWT.require(algorithm).build();

verifierMap.put(signingToken, verifier);

}

}

}

DecodedJWT jwt = verifier.verify(tokenString);

return jwt;

}

private static Algorithm getAlgorithm(String signingToken) {

Algorithm algorithm = algorithmMap.get(signingToken);

if (algorithm == null) {

synchronized (algorithmMap) {

algorithm = algorithmMap.get(signingToken);

if (algorithm == null) {

algorithm = Algorithm.HMAC512(signingToken);

algorithmMap.put(signingToken, algorithm);

}

}

}

return algorithm;

}

}

登录流程

登录

import gnl.alibaba.common.api.BaseResponse;

import gnl.alibaba.common.auth.Hash;

import gnl.alibaba.common.auth.Sign;

import gnl.alibaba.common.dto.UserDto;

import gnl.alibaba.common.exception.PermissionDeniedException;

import org.springframework.web.bind.annotation.GetMapping;

import org.springframework.web.bind.annotation.RequestMapping;

import org.springframework.web.bind.annotation.RestController;

@RestController

@RequestMapping("/auth")

public class AccountController {

@GetMapping("/token")

public BaseResponse token(String account, String password) {

//根据账户密码查询用户

UserDto userDto = selectAccount(account, password);

if (userDto == null) {

throw new PermissionDeniedException("用户名或密码错误");

}

//根据用户信息和密钥得到token

String token = Sign.generateSessionToken(userDto, "secret", 24 * 60 * 60 * 1000L);

return new BaseResponse<>(token);

}

private UserDto selectAccount(String account, String password) {

//加密密码为对密码进行一次HmacSHA256,密钥为secret

password = Hash.encode("secret", password);

if ("gnl".equals(account) && "4a83854cf6f0112b4295bddd535a9b3fbe54a3f90e853b59d42e4bed553c55a4".equals(password)) {

UserDto user = new UserDto();

user.setId("1");

user.setAccount(account);

user.setName("郭南林");

user.setGender((byte) 1);

return user;

}

return null;

}

}

验证登录

这里登录验证放在SpringCloudGateway网关里了,验证通过后,将解析出来的userId存入header中,转发给相应的服务

import com.alibaba.fastjson.JSON;

import com.auth0.jwt.exceptions.TokenExpiredException;

import com.auth0.jwt.interfaces.DecodedJWT;

import gnl.alibaba.common.api.BaseResponse;

import gnl.alibaba.common.api.ResultCode;

import gnl.alibaba.common.auth.Sign;

import gnl.alibaba.gateway.http.RequestDataExtractor;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.springframework.cloud.gateway.filter.GatewayFilterChain;

import org.springframework.cloud.gateway.filter.GlobalFilter;

import org.springframework.core.Ordered;

import org.springframework.core.io.buffer.DataBuffer;

import org.springframework.http.HttpHeaders;

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.web.server.ServerWebExchange;

import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;

import java.util.HashSet;

import java.util.function.Consumer;

@Component

public class TokenFilter implements GlobalFilter, Ordered {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@Override

public int getOrder() {

// 返回值用来指定执行的顺序,数字越小,优先级越高

return 0;

}

@Override

public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {

ServerHttpRequest request = exchange.getRequest();

//获取访问路劲

String path = RequestDataExtractor.getPath(request);

//校验是否是可以直接访问的路径,例如登录接口

if (isPass(path)) {

return chain.filter(exchange);

}

//从请求头中获取token

String token = RequestDataExtractor.getHeader(request, "token");

//校验token

DecodedJWT decodedJWT = null;

try {

decodedJWT = Sign.verifySessionToken(token, "secret");

} catch (TokenExpiredException e) {

return this.returnData(ResultCode.UN_AUTHORIZED.getCode(), "登录状态已失效,请重新登录", exchange);

} catch (Exception e) {

log.info(e.getMessage(), e);

return this.returnData(ResultCode.UN_AUTHORIZED.getCode(), "您还未登录哟", exchange);

}

//获取token中解析出的userId

String userId = decodedJWT.getClaims().get(Sign.CLAIM_USER_ID).asString();

//将userId存入header

Consumer httpHeaders = httpHeader -> {

httpHeader.set("userId", userId);

};

RequestDataExtractor.addHeader(exchange, httpHeaders);

return chain.filter(exchange);

}

/**

* 校验不需要token可以直接访问的路径

*/

private boolean isPass(String path) {

HashSet paths = new HashSet<>();

//这里可以设置不用token可以访问的路径

paths.add("/account-service/auth/token");

return paths.contains(path) ? true : false;

}

/**

* 返回值的封装

*/

private Mono returnData(Integer code, String msg, ServerWebExchange exchange) {

ServerHttpResponse response = exchange.getResponse();

BaseResponse data = new BaseResponse<>(code, msg);

byte[] datas = JSON.toJSONString(data).getBytes(StandardCharsets.UTF_8);

DataBuffer buffer = response.bufferFactory().wrap(datas);

response.setStatusCode(HttpStatus.OK);

response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");

return response.writeWith(Mono.just(buffer));

}

}

服务接收到请求获取请求头中的userId

import org.springframework.beans.factory.annotation.Autowired;

import javax.servlet.http.HttpServletRequest;

public class BaseController {

@Autowired

protected HttpServletRequest request;

public String getUserId(){

return request.getHeader("userId");

}

public String getHeader(String key){

return request.getHeader(key);

}

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值