1.首先了解一下Token

  • uid: 用户唯一身份标识
  • time: 当前时间的时间戳
  • sign: 签名, 使用 hash/encrypt 压缩成定长的十六进制字符串,以防止第三方恶意拼接
  • 固定参数(可选): 将一些常用的固定参数加入到 token 中是为了避免重复查数据库

2.token 验证的机制(流程)

  1. 用户登录校验,校验成功后就返回Token给客户端。
  2. 客户端收到数据后保存在客户端
  3. 客户端每次访问API是携带Token到服务器端。
  4. 服务器端采用filter过滤器校验。校验成功则返回请求数据,校验失败则返回错误码

3.使用SpringBoot搭建基于token验证

3.1 引入 POM 依赖

<!--Json web token-->
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.4.</version>
</dependency>

3.2  新建一个拦截器配置 用于拦截前端请求 实现   WebMvcConfigurer

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration
public class InterceptorConfig implements WebMvcConfigurer { @Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(authenticationInterceptor())
.addPathPatterns("/**");//拦截所有请求,通过判断是否有 @LoginRequired 注解 决定是否需要登录
} @Bean
public AuthenticationInterceptor authenticationInterceptor() {
return new AuthenticationInterceptor();
}
}

3.3 新建一个 AuthenticationInterceptor  实现HandlerInterceptor接口  实现拦截还是放通的逻辑

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.my_springboot.rbac.pojo.Admin;
import com.my_springboot.rbac.service.IAdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method; /**
* 拦截器去获取token并验证token*/
public class AuthenticationInterceptor implements HandlerInterceptor { @Autowired
private IAdminService adminService; @Override
public boolean preHandle(HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse, Object object) {
String token = httpServletRequest.getHeader ("token");// 从 http 请求头中取出 token
// 如果不是映射到方法直接通过
if (!(object instanceof HandlerMethod)) {
return true;
}
HandlerMethod handlerMethod = (HandlerMethod) object;
Method method = handlerMethod.getMethod ();
//检查是否有@passtoken注解,有则跳过认证
if (method.isAnnotationPresent (PassToken.class)) {
PassToken passToken = method.getAnnotation (PassToken.class);
if (passToken.required ()) {
return true;
}
}
//检查有没有需要用户权限的注解
if (method.isAnnotationPresent (UserLoginToken.class)) {
UserLoginToken userLoginToken = method.getAnnotation (UserLoginToken.class);
if (userLoginToken.required ()) {
// 执行认证
if (token == null) {
throw new RuntimeException ("无token");
}
// 获取 token 中的 user id
String adminId;
try {
adminId = JWT.decode (token).getAudience ().get (0);
} catch (JWTDecodeException j) {
throw new RuntimeException ("401");
}
Admin admin = adminService.getById (adminId);
if (admin == null) {
throw new RuntimeException ("用户不存在");
}
// 验证 token
JWTVerifier jwtVerifier = JWT.require (Algorithm.HMAC256 (admin.getPassword ())).build ();
try {
jwtVerifier.verify (token);
} catch (JWTVerificationException e) {
throw new RuntimeException ("401");
}
return true;
}
}
return true;
} @Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { } @Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { }
}

3.4 新建两个注解 用于标识请求是否需要进行Token 验证

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 需要登录才能进行操作的注解UserLoginToken*/ @Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface UserLoginToken { boolean required() default true;
}
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; /**
* 用来跳过验证的PassToken*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken { boolean required() default true;
}

3.5 新建一个Service用于下发Token

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.my_springboot.rbac.pojo.Admin;
import org.springframework.stereotype.Service; import java.util.Date; /**
* 下发token*/
@Service
public class TokenService { public String getToken(Admin admin) {
Date start = new Date ();
long currentTime = System.currentTimeMillis () + 60 * 60 * 1000;//一小时有效时间
Date end = new Date (currentTime);
return JWT.create ().withAudience (admin.getId ()).withIssuedAt (start)
.withExpiresAt (end)
.sign (Algorithm.HMAC256 (admin.getPassword ()));
}
}

3.6 新建一个工具类 用户从token中取出用户Id

import com.auth0.jwt.JWT;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest; /**
* token工具类*/
public class TokenUtil {
public static String getTokenUserId() {
String token = getRequest().getHeader("token");// 从 http 请求头中取出 token
String userId = JWT.decode(token).getAudience().get(0);
return userId;
} /**
* 获取request
*
* @return
*/
public static HttpServletRequest getRequest() {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
return requestAttributes == null ? null : requestAttributes.getRequest();
}
}

以上。

从零开始的SpringBoot项目 ( 八 ) 实现基于Token的用户身份验证的更多相关文章

  1. Springboot token令牌验证解决方案 在SpringBoot实现基于Token的用户身份验证

    1.首先了解一下Token 1.token也称作令牌,由uid+time+sign[+固定参数]组成: uid: 用户唯一身份标识 time: 当前时间的时间戳 sign: 签名, 使用 hash/e ...

  2. 在ASP.NET Web API 2中使用Owin基于Token令牌的身份验证

    基于令牌的身份验证 基于令牌的身份验证主要区别于以前常用的常用的基于cookie的身份验证,基于cookie的身份验证在B/S架构中使用比较多,但是在Web Api中因其特殊性,基于cookie的身份 ...

  3. 基于token的后台身份验证(转载)

    几种常用的认证机制 HTTP Basic Auth HTTP Basic Auth简单点说明就是每次请求API时都提供用户的username和password,简言之,Basic Auth是配合RES ...

  4. 从零开始的SpringBoot项目 ( 五 ) 整合 Swagger 实现在线API文档的功能

    综合概述 spring-boot作为当前最为流行的Java web开发脚手架,越来越多的开发者选择用其来构建企业级的RESTFul API接口.这些接口不但会服务于传统的web端(b/s),也会服务于 ...

  5. 从零开始的SpringBoot项目 ( 六 ) 整合 MybatisPlus 实现代码自动生成

    1.添加依赖 <!-- MySQL数据库 --> <dependency> <groupId>mysql</groupId> <artifactI ...

  6. 从零开始的SpringBoot项目 ( 四 ) 整合mybatis

    一.创建一个SpringBoot项目 从零开始的SpringBoot项目 ( 二 ) 使用IDEA创建一个SpringBoot项目 二.引入相关依赖 <!--mysql数据库驱动--> & ...

  7. 5分钟搞懂:基于token的用户认证

    https://www.qikegu.com/easy-understanding/880 用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供 ...

  8. WebApi基于Token和签名的验证

    最近一段时间在学习WebApi,涉及到验证部分的一些知识觉得自己并不是太懂,所以来博客园看了几篇博文,发现一篇讲的特别好的,读了几遍茅塞顿开(都闪开,我要装逼了),刚开始读有些地方不理解,所以想了很久 ...

  9. Nginx集群之基于Redis的WebApi身份验证

    目录 1       大概思路... 1 2       Nginx集群之基于Redis的WebApi身份验证... 1 3       Redis数据库... 2 4       Visualbox ...

随机推荐

  1. Python常用标准库之datetime、random、hashlib、itertools

    库:具有相关功能模块的集合 import sys.builtin_module_names #返回内建模块的名字modules 查看所有可用模块的名字 1.1.1获取当前日期和时间 from date ...

  2. PHP fgetcsv() 函数

    定义和用法 fgetcsv() 函数从打开的文件中解析一行,校验 CSV 字段. fgetcsv() 函数会在到达指定长度或读到文件末尾(EOF)时(以先到者为准),停止返回一个新行. 该函数如果成功 ...

  3. PHP asXML() 函数

    实例 格式化 XML(版本 1.0)中的 SimpleXML 对象的数据: <?php$note=<<<XML<note>高佣联盟 www.cgewang.com& ...

  4. luogu P2183 [国家集训队]礼物

    LINK:礼物 n个物品 m个人 每个人要分得wi 个物品 每个物品互异 分给每个人的物品不分顺序 求方案数. \(n,p\leq 1e9 m\leq 5\) 方案数 那显然是 第一个人拿了w1件物品 ...

  5. markdown利器-小书匠

    markdown利器-小书匠 为什么要用markdown语法编写文档? 编写文档的好处这里就不多说了.相信很多人都会在一些博客网站上发布自己的博客,那么怎么能使得自己的博客内容更加具有通用性呢?正如j ...

  6. 浅谈Mybatis持久化框架在Spring、SSM、SpringBoot整合的演进及简化过程

    前言 最近开始了SpringBoot相关知识的学习,作为为目前比较流行.用的比较广的Spring框架,是每一个Java学习者及从业者都会接触到一个知识点.作为Spring框架项目,肯定少不了与数据库持 ...

  7. 初识分布式:MIT 6.284系列(一)

    前言 本系列是源于「码农翻身」所属知识星球发起的读书活动,由大佬 @我的UDP不丢包 推荐而来,这次的读书活动有一些另类,我们抛弃了传统的书籍,开始攻略最高学府的研究生顶级课程 <6.824&g ...

  8. SqlServer 多表连接、聚合函数、模糊查询、分组查询应用总结(回归基础)

    --exists 结合 if else 以及 where 条件来使用判断是否有数据满足条件 select * from Class where Name like '%[1-3]班' if (not ...

  9. SSH全注解-annotation详细配置

    web.xml的配置: <!--Spring的装载器 --> <listener> <listener-class> org.springframework.web ...

  10. 牛!Python 也能实现图像姿态识别溺水行为了!

    作者 | 李秋键 责编 | Carol 封图 | CSDN 下载自视觉中国 众所周知随着人工智能智能的发展,人工智能的落地项目也在变得越来越多,尤其是计算机视觉方面. 很多人学习python,不知道从 ...