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. Flask+微信公众号开发(接入指南)

    目录 一.注册公众号 二.启用开发者 三.配置服务器配置 四.开发自己的需求 五.写在最后 一.注册公众号 具体的注册过程,根据官方文档一步一步来即可.这里需注意的是订阅号还是服务号:有些比较好的开发 ...

  2. Python List insert()方法

    描述 insert() 函数用于将指定对象插入列表的指定位置.高佣联盟 www.cgewang.com 语法 insert()方法语法: list.insert(index, obj) 参数 inde ...

  3. PHP atan() 函数

    实例 通过 atan() 函数返回不同数的反正切: <?phpecho(atan(0.50) . "<br>");echo(atan(-0.50) . " ...

  4. Blob分析之 ball.hdev

    * ball.hdev: Inspection of Ball Bonding * 关闭窗体更新 dev_update_window ('off')*关闭窗体dev_close_window ()*打 ...

  5. Maven知识记录(一)初识Maven私服

    Maven知识记录(一)初识Maven私服 什么是maven私服 私服即私有的仓库.maven把存放文件的地方叫做仓库,我们可以理解成我门家中的储物间.而maven把存放文件的具体位置叫做坐标.我们项 ...

  6. mybatis plus 更新值为null的字段

    转载请注明出处: 由于mybatis plus调用默认的更新操作方法时,不更新值为空,null或默认值等得属性字段,只更新值为非null,非空非默认值的属性字段. 以下为mybatis plus sa ...

  7. Python Selenium 搭建Web UI自动化

    Python搭建UI自动化环境 下载Python3 Python官网 PyCharm 环境配置 安装Python 勾选Add Python to PATH,一直下一步. 验证:CMD输入Python ...

  8. 灰帽黑客 基本的Linux漏洞攻击

    有两个重要的寄存器负责处理堆栈:基址指针(EBP)和栈指针(ESP),EBP指向当前进程的当前栈帧的底部,ESP则总是指向栈顶 当调用函数的时候,会导致程序流跳转.在汇编代码调用函数时,将发生以下三件 ...

  9. 用Python一键生成炫酷九宫格图片,火了朋友圈

  10. Python实现各类验证码识别

    项目地址: https://github.com/kerlomz/captcha_trainer 编译版下载地址: https://github.com/kerlomz/captcha_trainer ...