私有声明是由提供者和消费者共同定义的声明。 一般不建议存储敏感信息,因为base64是对称解密的游戏登录验证源码,这意味着这部分信息可以归类为明文信息。
签名
jwt的第三部分是护照信息
这部分需要使用base64加密的header和base64加密的payload并连接形成字符串,然后通过header中声明的加密方法对水密组合进行加密,然后jwt的第三部分是形成。
密钥存储在服务器上。 服务器将生成令牌并根据此密钥进行验证,因此需要对其进行保护。
让我们集成 SpringBoot 和 JWT
引入JWT依赖,因为是基于Java的,所以需要java-jwt
com.auth0
java-jwt
3.4.0
需要自定义两个注解
PassToken用于跳过验证,注解参考:SpringBoot常用注解及原理!
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
boolean required() default true;
}
需要登录才能执行操作的注解UserLoginToken
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken {
boolean required() default true;
}
@Target注解的目的
@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包
@Retention注解的保留位置
只需自定义一个实体类User,使用lombok就可以简化实体类的编译。
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
String Id;
String username;
String password;
}
需要编写token生成方法
public String getToken(User user) {
String token="";
token= JWT.create().withAudience(user.getId())
.sign(Algorithm.HMAC256(user.getPassword()));
return token;
}
}
Algorithm.HMAC256():使用HS256生成令牌。 密钥是用户的密码。 唯一密钥可以保存在服务器上。
withAudience()存储了token中需要保存的信息。 这里我将用户 ID 存储在令牌中。
接下来需要编写一个拦截器来获取token并验证token。
要实现拦截器,需要实现HandlerInterceptor接口
HandlerInterceptor套接字主要定义了三个方法
1.boolean preHandle():
预处理反弹方法实现了处理器的预处理。 第三个参数是响应处理器,自定义Controller。 返回值为true则继续处理(如调用下一个拦截器或处理器)或者然后执行postHandle()和afterCompletion(); false表示进程被中断,不会继续调用其他拦截器或处理器来中断执行。
2.void postHandle():
后处理反弹方法实现了处理器的后处理(在视图返回渲染之前调用DispatcherServlet)。 这时我们可以通过modelAndView(模型和视图对象)来处理模型数据或者处理视图。 modelAndView 也可能为 null。 。
3.void afterCompletion():
整个请求处理完毕后的反弹方法只有在当前对应Interceptor的preHandle()返回值为true时才能执行,即DispatcherServlet渲染对应的视图然后执行。 用于资源清理。
整个请求通过反弹技术来解决。比如性能监控中,我们可以在这里记录结束时间并输出消耗时间,也可以进行一些资源清理,类似于try-catch-finally中的finally,但是只调用处理器执行链
主要流程:
从http请求头中取出token,判断是否映射到方法上。 检查是否有passtoken注释。 如果不是游戏登录验证源码,则跳过认证,检查是否有需要用户登录的注解。 如果不是,则需要将其取出并进行验证。 如果认证通过,就可以访问。 若不通过,将上报相关报告。 错误消息配置拦截器
在配置类上添加@Configuration注解,表明该类是一个配置类,将会作为SpringBean添加到IOC容器中。拦截器请看这里>:Spring Boot实战:拦截器和过滤器
@Configuration
public class InterceptorConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**"); // 拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
虽然抽象类WebMvcConfigurerAdapter没有以任何方式实现,但它只是实现了socket空。
WebMvcConfigurer中的所有方法不提供任何业务逻辑处理。 这样的设计恰到好处,让我们不必去实现这些我们不用的方法。 它们都是由WebMvcConfigurerAdapter抽象类实现的。 如果我们需要针对特定的方法进行逻辑处理,只需要在WebMvcConfigurerAdapter子类中使用@Override对应的方法即可。
注意:WebMvcConfigurerAdapter 在 Spring Boot 2.0 和 Spring 5.0 中已被废弃。 网上说会继承WebMvcConfigurationSupport,但是尝试了一下,还是过期了。
解决方案:
直接实现WebMvcConfigurer(官方推荐)
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");
}
@Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}
InterceptorRegistry中的addInterceptor需要一个实现HandlerInterceptor套接字的拦截器实例。 addPathPatterns方法用于设置拦截器的过滤路径规则。
这里我拦截所有请求,通过判断是否有@LoginRequired注解来判断是否需要登录。
数据访问socket添加登录操作注解
如果不添加注解,则默认不进行验证。 登录socket通常是不验证的。在getMessage()中,我添加了登录注解,表示socket必须登录才能获取token,将token添加到请求头并通过验证后才能访问。
下面进行测试,启动项目,使用postman测试socket
无需令牌即可访问 api/getMessage 套接字
我在这里使用统一的异常处理,所以我只看到错误消息。
登录下方获取令牌
登录操作我没有添加验证注解,直接访问即可。
将token添加到请求头中,再次访问api/getMessage接口
注意:这里的key一定不能错,因为拦截器中取的是关键字token的值。 String token = httpServletRequest.getHeader("token");
添加token后,即可成功通过验证并访问socket。
Github项目源码地址: