首页 > 其他分享 >token验证的方法

token验证的方法

时间:2022-11-12 11:09:12浏览次数:83  
标签:return String 验证 校验 token user 注解 方法

统一token处理

排除token校验注解类
为不需要校验 token 的方法定义注解
@Documented //标记注解
@Target(ElementType.METHOD) //指定作用在方法上 对方法拦截
@Retention(RetentionPolicy.RUNTIME) //作用域 在运行时有效

NoAuthorization.java

import java.lang.annotation.*;

/**
* 包含该注解的方法 不需要校验token 直接放行
* @author 陌路
* @date 2022-03-19
* @apiNote token统一处理
*/
@Documented//标记注解
@Target(ElementType.METHOD) //指定作用在方法上 对方法拦截
@Retention(RetentionPolicy.RUNTIME) //作用域 在运行时有效
public @interface NoAuthorization {

/** ---------@定义注解---------
* 元注解
* @Target({METHOD,TYPE}) 表示这个注解可以用用在类/接口上,还可以用在方法上
* @Retention(RetentionPolicy.RUNTIME) 表示这是一个运行时注解,即运行起来之后,
* 才获取注解中的相关信息,而不像基本注解如@Override 那种。
* @Inherited 表示这个注解可以被子类继承
* @Documented 表示当执行javadoc的时候,本注解会生成相关文档(标记)
*
* 自定义注解的使用:
* 该注解定义好之后,将该注解加在方法上@NoAuthorization即可,
* 若注解中存在属性需要赋值,则直接可以在注解中赋值即可,
* eg:public @interface ZjObj{
* String name();
* Integer sex();
* }
* eg: @ZjObj(属性="值") -> @ZjObj(name="张三",sex=1)
*
* 也可这样定义注解,效果都是一样的
* @Target(value = { ElementType.ANNOTATION_TYPE })
* @Retention(RetentionPolicy.RUNTIME)
* @Inherited
* @Documented
*
* ---------@解析注解@使用注解---------
* * 若注解中有属性,则可以直接通过反射来获取属性值
* * 相关配置信息本来是以属性的方式存放的,现在改为了以注解的方式
* *
* * @解析注解: 通过反射,获取这个类上的注解对象
* * ZjObj zjObj = class.foraName(ZjObj.class);
* * 拿到注解对象之后,通过方法,获取各个注解元素的值:
* * String name = zjObj.name();
* * Integer sex = zjObj.sex ();
*/
}

本地线程缓存类
封装获取当前登录人数据信息类

在 TokenInterceptor 将获取到的user数据信息添加到 本地线程UserThreadLocal中去
TokenInterceptor类中实现了HandlerInterceptor拦截器,对请求进行了拦截
并对token进行了校验,token有效就会把user数据信息存储到UserThreadLocal当前类中
通过调用该类的get()方法时,即可获取到user的数据信息

UserThreadLocal.java

/**
* 获取当前登录人信息
* @author 陌路
* @date 2022-03-19
* @apiNote 封装当前登录用户信息
*/
public class UserThreadLocal {
private static final ThreadLocal<User> LOCAL = new ThreadLocal<User>();
/**
* `TokenInterceptor`类中实现了`HandlerInterceptor`拦截器,对请求进行了拦截
* 并对token进行了校验,token有效就会把`user`数据信息存储到当前类中
* 通过调用该类的`get()`方法时,即可获取到`user`的数据信息
*/

//构造方法私有化,不运行外部实例化该对象
private UserThreadLocal() {
}
public static void set(User user) {
LOCAL.set(user);
}
public static User get() {
return LOCAL.get();
}
}

token校验类
定义方法的请求拦截器,判断用户请求的方法是否需要校验token信息,preHandle 前置拦截
此拦截器是在执行用户请求的方法前拦截到的,该拦截器结束之前,不会执行用户请求的方法
当该拦截器执行完成后,根据拦截器返回结果(true|false)判断是否继续执行用户的请求
preHandle 返回 false 时,用户请求将不再继续执行,为 true 时校验通过才会继续执行

思路:
首先判断用户请求的方法中是否包含了@NoAuthorization注解 若包含了该注解 则放行
如果不包含该注解,说明需要对token进行校验,继续执行下面的校验代码
校验:首先判断请求头中是否包含 "Authorization"请求头数据 不包含则结束校验 不予访问
若包含,则需要解析token数据拿到user对象,不为空就把当前user对象存储到UserThreadLocal线程中去并返回true验证成功

TokenInterceptor.java

import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
* 请求拦截器 统一token校验
* @author 陌路
* @date 2022-03-19
* @apiNote 统一token校验
*/
@Component
public class TokenInterceptor implements HandlerInterceptor {

@Autowired
private UserService userService;

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
/** 思路
* 首先判断请求的方法中是否包含了@NoAuthorization注解 若包含了此注解 则不作处理
* 包含该@NoAuthorization注解 表示不需要做token的验证 直接return true 放行即可
* 如果不包含该注解,说明需要对token进行校验,则继续执行下面的代码
* 校验:首先判断请求头中是否包含 "Authorization" 请求头数据 不包含则结束校验 不予访问
* 若包含 则需要解析token数据 拿到 user 对象,判断user对象是否为null
* 为null 说明不存在,直接返回false,不予访问,重新登录
* 不为空 则需要把当前user对象存储到 UserThreadLocal 线程中去 并返回true 验证成功
*/
// 如果 handler 是 HandlerMethod 类型,则把 handler(Object类型)转为HandlerMethod类型
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
// 获取将要访问的方法名,根据方法名获取方法上的 NoAuthorization 注解,判断该注解是否存在
NoAuthorization noAuthorization = handlerMethod
.getMethod()
.getAnnotation(NoAuthorization.class);
//若方法中存在该 NoAuthorization 注解,则表示无需校验 返回true
if (noAuthorization != null) {
return true;
}
}
//获取到请求头中的头信息(token)
String token = request.getHeader("Authorization");
//判断token是否存在
if (StringUtils.isNotEmpty(token)) {
//存在则根据token解析user数据
User user = this.userService.queryUserByToken(token);
//判断解析的user数据是否为null
if (null != user) {
//不为空 则将user信息存储到线程中
UserThreadLocal.set(user);
return true;
}
}
//若请求头中不存在Authorization 直接返回false 提示状态码401无权限
response.setStatus(401);
return false;
}
}

Service解析token实现类
解析token数据,把token数据解析为user对象
解析完成后重置缓存时长,将缓存时间重新增加到一个小时

/**
* 解析token,获取user数据信息
* 对token进行检测,如果token存在,则解析出user数据信息
* 如果token不存在,则return null
* 除注册和发送验证码外不需要检测token外,其他功能均需要检测token
*/
@Override
public User queryUserByToken(String token) {
try {
// 生成redisKey获取当前登陆人信息
String redisTokenKey = "TOKEN_" + token;
// 获取缓存数据
String cacheData = this.redisTemplate.opsForValue().get(redisTokenKey);
if (StringUtils.isNotEmpty(cacheData)) {
// 刷新时间
this.redisTemplate.expire(redisTokenKey, 1, TimeUnit.HOURS);
//反序列化,将JSON数据转化为user对象返回
return MAPPER.readValue(cacheData, User.class);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

如果是分布式系统,需要远程调用SSO服务验证token的,可以加上下面的代码
编码格式和超时时间配置类(远程调用支持类)

配置 RestTemplate 模板,设置服务远程调用过程中的编码格式

添加消息数据的字符集格式、连接超时时间和数据获取超时时间

RestTemplateConfig.java

/**
* RestTemplate模板配置类
* @author 陌路
* @date 2022-03-19
* @apiNote 设置模板的字符集、链接超时时间和获取超时时间
*/
@Configuration
public class RestTemplateConfig {

@Bean
public RestTemplate restTemplate(ClientHttpRequestFactory factory) {
RestTemplate restTemplate = new RestTemplate(factory);
// 支持中文编码,getMessageConverters消息转换器,将字符集设置为 UTF-8
restTemplate.getMessageConverters()
.set(1, new StringHttpMessageConverter(Charset.forName("UTF-8")));
return restTemplate;
}

@Bean
public ClientHttpRequestFactory simpleClientHttpRequestFactory() {
SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
// 设置数据获取的超时时间,单位为ms
factory.setReadTimeout(5000);
// 设置连接超时时间,单位为ms
factory.setConnectTimeout(5000);
return factory;
}
}

远程调用Service类

远程服务调用,验证和获取token数据(调用SSO单点登录中接口)

url:url为SSO单点登录服务器的IP地址和端口加协议的全名地址

eg:​​http://47.101.xxx.xxx:80​​ 本地:eg:http://127.0.0.1:80

该方法涉及了服务的远程调用过程,需要使用 RestTemplate 中的 .getForObject();

把上面的service解析token的方法改为下面这段代码

/**
* 解析Token
* 调用SSO接口进行解析token
* @param token
* @return
*/
public User queryUserByToken(String token) {
try {
// 返回一串JSON字符串,url为SSO单点登录服务器的ip地址和端口eg:http://127.0.0.1:80
String url = "http://192.168.10.188:18080";
String jsonData = this.restTemplate.getForObject(url + "/user/{token}", String.class, token);
// 如果查询到就返回user对象 查询不到就返回null
if (StringUtils.isNotEmpty(jsonData)) {
// MAPPER.readValue方法将JSON字符串转化为对象 并返回
return MAPPER.readValue(jsonData, User.class);
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

controller控制器接口

远程服务调用,被调用的接口(SSO单点登录中的控制器接口)

远程服务调用此接口需要使用全名地址:
协议://ip地址:端口号 ​​http://ip:port​​ (​​https://ip:port​​)

下面的controller作为SSO中被远程调用的测试接口(请根据实际接口调用)

/**
* 验证token
* @param token
* @return
*/
@GetMapping("{token}")
public User queryUserByToken(@PathVariable("token") String token) {
//根据token把查询到的结果返回
return this.userService.queryUserByToken(token);
}

标签:return,String,验证,校验,token,user,注解,方法
From: https://blog.51cto.com/u_15733182/5846533

相关文章

  • eclipse打开时候,发现之前的一些工程项目不见了的解决方法
    emm,最近在学习安装STS,一个springboot的插件,谁觉这个行业变化之迅速,不多学点东西,怎么混得下去(委屈),本来eclipse好好的,所以就倒腾了一番。安装插件没有安装成功,倒是eclipse默......
  • odoo网站,不同语言,显示不同内容的方法
    1:通过菜单,或者page找到网站内容对应的, ir.ui.veiw的key2:编辑视图的xml内容,用t-if, lang获取网站语言代码,根据语言内容,显示不同内容.......
  • 5.信号处理(1) --常用信号平滑去噪的方法
    前言:最近研究汽车碰撞的加速度信号,在信号的采集过程中难免遇到噪音,导致信号偏差,为了更好的反映系统情况,故常需要信号去噪,本文分享一些常用信号平滑去噪的方法。关键字:信号;去......
  • C# 使用CancellationTokenSource取消多线程
    原文网址:https://blog.csdn.net/xwnxwn/article/details/115670973如下:我们点击一个按钮开启线程,然后点击取消按钮取消该线程的执行    CancellationTokenSourcect......
  • vue的$nextTick方法
    问题:异步代码没有执行,但是同步代码已经完成逻辑,所以就需要使用$nextTick来等待dom完毕后再执行同步代码解决方法:使用nextTick()等待dom更新完毕后,在执行对应的回调......
  • Pytest接口测试框架实战项目搭建(二)—— tools公共方法封装
    一、前言在项目中我们要频繁地用到log日志、request请求方法、断言等,所以我们可以把这些常用的方法封装成日志,下面将逐个文件讲述下,不会讲太细,但会把源码贴出来,还有一......
  • 设计模式学习(十四):模板方法
    设计模式学习(十四):模板方法作者:Grey原文地址:博客园:设计模式学习(十四):模板方法CSDN:设计模式学习(十四):模板方法模板方法模板方法是一种行为型模式。假设我们要实现一个游......
  • vite不能用@做为路径的解决方法
    vite创建vue3后,发现原来用@做为路径的不能用了,报错信息是Internalservererror:Failedtoresolveimport"@在网上查了一下资料,解决方法如下首先安装pathnpmins......
  • mac git远程仓库错误解决方法
    mac更新后不知道怎么回事,git时出现了Permissiondenied(publickey).经查询后得出原因1、首先给git进行config的配置gitconfig--globaluser.name你的用户名gi......
  • 简单进行Springboot Beans归属模块单元的统计分析方法
    简单进行SpringbootBeans归属模块单元的统计分析方法背景基于Springboot的产品变的复杂之后启动速度会越来越慢.公司同事得出一个结论.beans数量过多会导致启动速......