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. 线程_互斥锁_Lock及fork创建子进程

    """ 创建锁 mutex = threading.Lock() 锁定 mutex.acquire([blocking]) 当blocking为True时,当前线程会阻塞 ...

  2. Python File seek() 方法

    概述 seek() 方法用于移动文件读取指针到指定位置.高佣联盟 www.cgewang.com 语法 seek() 方法语法如下: fileObject.seek(offset[, whence]) ...

  3. 找回 Virtuoso 中的缩放和角度

    https://www.cnblogs.com/yeungchie/ 打开要缩放的版图 CIW 中运行:dbCreateXformPCell(geGetEditCellView() geGetEdit ...

  4. 51nod 1584 加权约数和 约数和函数小trick 莫比乌斯反演

    LINK:加权约数和 我曾经一度认为莫比乌斯反演都是板子题. 做过这道题我认输了 不是什么东西都是板子. 一个trick 设\(s(x)\)为x的约数和函数. 有 \(s(i\cdot j)=\sum ...

  5. CF804D Expected diameter of a tree 树的直径 根号分治

    LINK:Expected diameter of a tree 1e5 带根号log 竟然能跑过! 容易想到每次连接两个联通快 快速求出直径 其实是 \(max(D1,D2,f_x+f_y+1)\) ...

  6. Workerman学习笔记(一)初步认识

    本文只是概念性的知识,内容比较零散,下篇文章再进行代码分析. Workerman是什么,他的优势在哪? 官方给的解释是高性能socket框架,我的个人理解是实现多进程的通讯的服务框架. 与传统的PHP ...

  7. 从零写一个Asp.net core手脚架(模型验证)

    一个asp.net core项目,一定包含了各种的实体,在RESTful api里面,有很多的参数传递,不建立实体则大量的参数需要自定验证正确性,并且Action上面会写的密密麻麻的参数 在asp.n ...

  8. canvas小画板--(1)平滑曲线

    功能需求 项目需求:需要实现一个可以自由书写的小画板 简单实现 对于熟悉canvas的同学来说,这个需求很简单,短短几十行代码就能实现: <!doctype html> <html& ...

  9. ORACLE在linux下的启动方法

    一.启动方法 方法1: Sql代码 cd $ORACLE_HOME/bin #进入到oracle的安装目录  ./dbstart #重启服务器  ./lsnrctl start #重启监听器 ---- ...

  10. 干!一张图整理了 Python 所有内置异常

    在编写程序时,可能会经常报出一些异常,很大一方面原因是自己的疏忽大意导致程序给出错误信息,另一方面是因为有些异常是程序运行时不可避免的,比如在爬虫时可能有几个网页的结构不一致,这时两种结构的网页用同一 ...