当前位置:网站首页>项目实战四:用户登录及token访问验证(reids+jwt)
项目实战四:用户登录及token访问验证(reids+jwt)
2022-06-26 18:25:00 【cc_南柯一梦】
1、注册中心,配置中心,网关,Feign等可以参考以下文章
【1】:nacos:https://blog.csdn.net/qq_28326501/article/details/117822745
【2】:网关:https://blog.csdn.net/qq_28326501/article/details/118225407
【3】:Feign:https://blog.csdn.net/qq_28326501/article/details/118440999
【4】:redis:https://blog.csdn.net/qq_28326501/article/details/118346062
2:项目整体架构及说明
登录时通过jwt生成token返回给前端,同时token用redis控制过期。其余请求时需要在header中放入token。使用fegin过滤器进行统一验证。

3、登录获取token
主要方法:
【1】:service方法:
/**
* 获取token
* @author cc
* @date 2021/6/30 22:35
* @param dto
* @return com.cc.common.vo.ReturnVo
*/
@Override
public ReturnVo login(UserDto dto) {
//判断用户名和密码是否正确
Boolean b = getUser(dto);
//正确生成token返回 //错误返回提示
if(b){
//生成token
String token = TokenUtil.getToken(dto.getName());
//token放入redis,用redis控制是否过期和刷新
boolean rs = redisUtil.set("cc" + dto.getName(), token, 300);
if (rs){
return ReturnVoUtil.success("登录成功", token);
}else{
return ReturnVoUtil.error("登录失败");
}
}else{
return ReturnVoUtil.error("用户名或密码错误");
}
}【2】:token工具类
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.12.1</version>
</dependency>package com.cc.oauth.utils;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import java.util.HashMap;
import java.util.Map;
/**
* @author cc
* @data 2021年06月28日 23:34
*/
public class TokenUtil {
//自定义密钥
private static String secretKey = "mysecret";
//签发者
private static String CC_KEY = "cc_jwt_token";
/**
* 生成签名
* @author cc
* @date 2021/6/28 23:35
*/
public static String getToken(String userName){
//获取密钥
Algorithm algorithm = getAlgorithm();
//添加自定义信息
Map map = new HashMap();
map.put("userName", userName);
//设置keyId
String keyId = "cc"+userName;
String token = JWT.create()
//.withIssuedAt(now)//当前时间
//.withExpiresAt(expiresDate)//过期时间
.withKeyId(keyId)
.withIssuer(CC_KEY)//签发者
.withHeader(map)//自定义信息
.sign(algorithm);//密钥
return token;
}
/**
* 解析签名
* @author cc
* @date 2021/6/28 23:35
*/
public static String parseToken(String token){
String msg = null;
//获取密钥
Algorithm algorithm = getAlgorithm();
JWTVerifier jwtVerifier = JWT.require(algorithm)
.withIssuer(CC_KEY)//签发者
.build();
DecodedJWT jwt = jwtVerifier.verify(token);
String userName = jwt.getHeaderClaim("userName").as(String.class);
return userName;
}
/**
* 获取自定义密钥
* @author cc
* @date 2021/6/29 17:01
*/
private static Algorithm getAlgorithm(){
Algorithm algorithm = Algorithm.HMAC256(secretKey);
return algorithm;
}
}
【3】:Controller方法
/**
* 登录获取token
* @author cc
* @date 2021/6/30 22:31
* @param dto
* @return com.cc.common.vo.ReturnVo
*/
@RequestMapping("/login")
public ReturnVo login(@RequestBody @Validated({Set.class, List.class}) UserDto dto){
ReturnVo login = loginService.login(dto);
return login;
}4、token校验和网关过滤器
【1】:LoginFiter
package com.cc.gateway.filter;
import com.cc.common.dto.UserDto;
import com.cc.common.utils.JSONUtils;
import com.cc.common.utils.ReturnVoUtil;
import com.cc.common.vo.ReturnVo;
import com.cc.gateway.feign.OauthFeign;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.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.util.List;
/**
* 访问token验证过滤器
* @author cc
* @data 2021年06月30日 17:47
*/
@Component
public class LoginFilter implements GlobalFilter, Ordered {
@Autowired
private OauthFeign oauthFeign;
@Value("${mysettings.skip-url}")
private List<String> skipUrl;
/**
* 核心方法
* @author cc
* @date 2021/6/30 17:50
* @param exchange
* @param chain
* @return reactor.core.publisher.Mono<java.lang.Void>
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
//从上下文中取出request和response对象
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
//获取请求url
String url = request.getURI().getPath();
url = url.substring(4,url.length());
//判断是否不验证token直接放行
boolean contains = skipUrl.contains(url);
if(contains){
//是,直接放行
return chain.filter(exchange);
}else{
//获取请求头中token进行token验证
List<String> tokens = request.getHeaders().get("token");
ReturnVo<Boolean> vo = ReturnVoUtil.error("请登录", false);
String token = null;
if(tokens != null){
token = tokens.get(0);
UserDto dto = new UserDto();
dto.setToken(token);
//token验证
vo = oauthFeign.checkToken(dto);
}
if(vo.getData()){
// token正确,刷新redis过期时间,同时放⾏
return chain.filter(exchange);
}else{
//token错误
response.setStatusCode(HttpStatus.UNAUTHORIZED);//状态码
String s = JSONUtils.beanToJson(vo);
DataBuffer wrap = response.bufferFactory().wrap(s.getBytes());
return response.writeWith(Mono.just(wrap));
}
}
}
@Override
public int getOrder() {
return 1;
}
}
【2】:token校验方法
/**
* 检查token是否正确
* @author cc
* @date 2021/6/30 22:35
* @return com.cc.common.vo.ReturnVo
*/
public ReturnVo checkToken(String token){
try{
//解析token 获取用户名称
String user = TokenUtil.parseToken(token);
//根据username从redis中看是否有此keytoken
String rtoken = (String) redisUtil.get("cc" + user);
if (StringUtils.isEmpty(rtoken)){
return ReturnVoUtil.success("token超时,请登录",false);
}
if (token.equals(rtoken)){
return ReturnVoUtil.success("token正确",true);
}else{
return ReturnVoUtil.success("token错误,请登录",false);
}
}catch (Exception e){
e.printStackTrace();
return ReturnVoUtil.error("token错误,请登录",false);
}
}
5、请求示例
登录获取token

有token

无token

边栏推荐
猜你喜欢

SSO微服务工程中用户行为日志的记录

Redis single sign on system + voting system

深入理解MySQL锁与事务隔离级别

Ethereum技术架构介绍

CD-CompactDisk

LeetCode 面试题29 顺时针打印矩阵

Clion编译catkin_ws(ROS工作空间包的简称)加载CMakeLists.txt出现的问题

(必须掌握的多线程知识点)认识线程,创建线程,使用Thread的常见方法及属性,以及线程的状态和状态转移的意义

Boyun, standing at the forefront of China's container industry

ISO documents
随机推荐
To: Apple CEO Cook: great ideas come from constantly rejecting the status quo
SSO微服务工程中用户行为日志的记录
How about opening an account at Guojin securities? Is it safe to open an account?
Eigen库计算两个向量夹角
Clion compiling catkin_ WS (short for ROS workspace package) loads cmakelists Txt problems
The cross compilation environment appears So link file not found problem
To: seek truth from facts
(multi threading knowledge points that must be mastered) understand threads, create threads, common methods and properties of using threads, and the meaning of thread state and state transition
Union, intersection and difference operations in SQL
Deep learning: numpy
Get and set settings in 26class
商品秒杀系统
Leetcode interview question 29 clockwise print matrix
Chinese (Simplified) language pack
ros::spinOnce()和ros::spin()的使用和区别
Summary of alter operation in SQL
Microservice architecture
行锁与隔离级别案例分析
分页查询、JOIN关联查询优化
将字符串B插入字符串A,有多少种插入办法可以使新串是一个回文串