首页 > 其他分享 >springboot集成JWT token验证

springboot集成JWT token验证

时间:2023-04-23 17:14:15浏览次数:43  
标签:map return springboot JWT Token token import resultWriter

登录模式

基于session登录

基于session的登录(有回话状态),用户携带账号密码发送请求向服务器,服务器进行判断,成功后将用户信息放入session,用户发送请求判断session中是否有用户信息,有的话放行,没有的话进行拦截,但是考虑到时App产品,牵扯到要判断用户的session,需要sessionID,还要根据sessionId来获取session,在进行校验,还有sessionId的一个存储等等

基于token登录

基于token的登录,是不存在回话状态,大概思路,在用户初次等路的时候,校验用户账号密码,成功后给其生成一个token,token=用户ID+时间戳+过期时间+一个自己平台规定的签名,使用jjwt生成一个令牌,然后对其进行存库,用户每次访问接口,都会在头部Headers中带上token,后来拦截器对其进行拦截,如果token为空或错误则让其登录,如果有token,获取token进行其解析,取出里面的用户ID,根据用户ID查询数据库中所存token,判断其是否正确,正确使其登录,错误则提示登录

实现

导入jar包

<!-- 生成token -->
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version>
</dependency>

创建token库

创建token实体类

package com.model.entity;
 
import lombok.Data;
 
/**
 * @Description: Token实体类
 * @author: z
 * @date: 2023/4/14 12:53
 */
@Data
public class TokenEntity {
 
 /* tokenId */
 private Long id;
 
 /* 用户ID */
 private Long userId;
 
 /* 刷新时间 */
 private int buildTime;
 
 /* token */
 private String token;
 
}

编写token的三个方法(添加、查询、修改)

package com.model.mapper;
 
import com.mode.entity.TokenEntity;
import org.apache.ibatis.annotations.Mapper;
 
/**
 * @Description: Token数据库持久层接口
 * @author: z
 * @date: 2023/4/14 12:53
 */
@Mapper
public interface TokenMapper {
 
 /* 添加token */
 void addToken(TokenEntity token);
 
 /* 修改token */
 void updataToken(TokenEntity token);
 
 /* 查询token */
 TokenEntity findByUserId(Long userId);
 
}

创建拦截器

package com.config.interceptor;
 
import com.model.entity.TokenEntity;
import com.model.mapper.TokenMapper;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
 
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
 
/**
 * @Description:拦截器
 * @author: z
 * @date: 2023/4/14 12:53
 */
public class LoginInterceptor implements HandlerInterceptor {
 
 @Autowired
 protected TokenMapper tokenMapper;
 //提供查询
 @Override
 public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
   throws Exception {}
 @Override
 public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3)
   throws Exception {}
 @Override
 public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception {
  //此处为不需要登录的接口放行
  if (arg0.getRequestURI().contains("/login") || arg0.getRequestURI().contains("/register") || arg0.getRequestURI().contains("/error") || arg0.getRequestURI().contains("/static")) {
   return true;
  }
  //权限路径拦截
  //PrintWriter resultWriter = arg1.getOutputStream();
  // TODO: 有时候用PrintWriter 回报 getWriter() has already been called for this response
  //换成ServletOutputStream就OK了
  arg1.setContentType("text/html;charset=utf-8");
  ServletOutputStream resultWriter = arg1.getOutputStream();
  final String headerToken=arg0.getHeader("token");
  //判断请求信息
  if(null==headerToken||headerToken.trim().equals("")){
   resultWriter.write("你没有token,需要登录".getBytes());
   resultWriter.flush();
   resultWriter.close();
   return false;
  }
  //解析Token信息
  try {
   Claims claims = Jwts.parser().setSigningKey("preRead").parseClaimsJws(headerToken).getBody();
   String tokenUserId=(String)claims.get("userId");
   long iTokenUserId = Long.parseLong(tokenUserId);
   //根据客户Token查找数据库Token
   TokenEntity myToken= tokenMapper.findByUserId(iTokenUserId);
 
   //数据库没有Token记录
   if(null==myToken) {
    resultWriter.write("我没有你的token?,需要登录".getBytes());
    resultWriter.flush();
    resultWriter.close();
    return false;
   }
   //数据库Token与客户Token比较
   if( !headerToken.equals(myToken.getToken()) ){
    resultWriter.print("你的token修改过?,需要登录");
    resultWriter.flush();
    resultWriter.close();
    return false;
   }
   //判断Token过期
   Date tokenDate= claims.getExpiration();
   int overTime=(int)(new Date().getTime()-tokenDate.getTime())/1000;
   if(overTime>60*60*24*3){
    resultWriter.write("你的token过期了?,需要登录".getBytes());
    resultWriter.flush();
    resultWriter.close();
    return false;
   }
 
  } catch (Exception e) {
   resultWriter.write("反正token不对,需要登录".getBytes());
   resultWriter.flush();
   resultWriter.close();
   return false;
  }
  //最后才放行
  return true;
 }
 
}

配置拦截器

package com.config;
 
import com.config.interceptor.LoginInterceptor;
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;
 
/**
 * @Description: 拦截器配置
 * @author: z
 * @date: 2023/4/14 12:53
 */
@Configuration
public class LoginConfiguration implements WebMvcConfigurer {
 
 /**
  * @Function: 这个方法才能在拦截器中自动注入查询数据库的对象
  * @author: z
  * @Date:  2023/4/14 12:53
  */
 @Bean
 LoginInterceptor loginInterceptor() {
  return new LoginInterceptor();
 }
 
 /**
  * @Function: 配置生成器:添加一个拦截器,拦截路径为login以后的路径
  * @author: z
  * @Date:  2023/4/14 12:53
  */
 @Override
 public void addInterceptors(InterceptorRegistry registry ){
  registry.addInterceptor(loginInterceptor()).addPathPatterns("/**").excludePathPatterns("/login", "/register", "/static");
 }
}

登录

controller层

 @PostMapping("/getlogin")
 public Result login(@RequestBody LoginQueryForm loginForm) {
  return Result.ok(userViewService.login(loginForm));
 }

serrvice层

@Override
 public Map<String, Object> login(LoginQueryForm loginForm) {
 
  Map<String, Object> map = new HashMap<>();
  //手机验证码登录
  if(!Util.isEmpty(loginForm.getPhoneCode())) {
   return phoneCodeLogin(loginForm, map);
  }
  //判断用户信息为空
  if (Util.isEmpty(loginForm.getPhone()) || Util.isEmpty(loginForm.getLoginPwd())) {
   return checkParameter(map);
  }
  //根据手机号查询user对象
  UserEntity user = userMapper.getUser(loginForm.getPhone());
 
  //判断用户不存在
  if (Util.isEmpty(user)) {
   map.put("code", UserStatusEnum.USER_NON_EXISTENT.intKey());
   map.put("msg", UserStatusEnum.USER_NON_EXISTENT.value());
   return map;
  }
  /* 判断密码 */
  if(!MD5Util.string2MD5(loginForm.getLoginPwd()).equals(user.getLoginPwd())){
   map.put("code", UserStatusEnum.PWD_ERROR.intKey());
   map.put("msg", UserStatusEnum.PWD_ERROR.value());
   return map;
  }
 
  //根据数据库的用户信息查询Token
  return operateToKen(map, user, user.getId());
 }

token操作

private Map<String, Object> operateToKen(Map<String, Object> map, UserEntity user, long userId) {
  //根据数据库的用户信息查询Token
  TokenEntity token = tokenmapper.findByUserId(userId);
  //为生成Token准备
  String TokenStr = "";
  Date date = new Date();
  int nowTime = (int) (date.getTime() / 1000);
  //生成Token
  TokenStr = creatToken(userId, date);
  if (null == token) {
   //第一次登陆
   token = new TokenEntity();
   token.setToken(TokenStr);
   token.setBuildTime(nowTime);
   token.setUserId(userId);
   token.setId(Long.valueOf(IdUtils.getPrimaryKey()));
   tokenmapper.addToken(token);
  }else{
   //登陆就更新Token信息
   TokenStr = creatToken(userId, date);
   token.setToken(TokenStr);
   token.setBuildTime(nowTime);
   tokenmapper.updataToken(token);
  }
  UserQueryForm queryForm = getUserInfo(user, TokenStr);
  /* 将用户信息存入session */
  /*SessionContext sessionContext = SessionContext.getInstance();
  HttpSession session = sessionContext.getSession();
  httpSession.setAttribute("userInfo", user);*/
  //返回Token信息给客户端
  successful(map);
  map.put("data", queryForm);
  return map;
 }

生成token

private String creatToken(Long userId, Date date) {
  SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
  JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT") // 设置header
    .setHeaderParam("alg", "HS256").setIssuedAt(date) // 设置签发时间
    .setExpiration(new Date(date.getTime() + 1000 * 60 * 60))
    .claim("userId",String.valueOf(userId) ) // 设置内容
    .setIssuer("lws")// 设置签发人
    .signWith(signatureAlgorithm, "签名"); // 签名,需要算法和key
  String jwt = builder.compact();
  return jwt;
 }

至此,token登录OK


原文章地址:
http://www.3qphp.com/java/framework/3303.html

标签:map,return,springboot,JWT,Token,token,import,resultWriter
From: https://www.cnblogs.com/1399z3blog/p/17347070.html

相关文章

  • Springboot yml配置参数加密 ,jasypt自定义解密器
    原文链接:https://www.cnblogs.com/JCcccit/p/16868137.html前言 最近项目组开始关注一些敏感数据的明文相关的事宜,其实这些东西也是都有非常成熟的解决方案。既然最近着手去解决这些事情,那么也顺便给还未了解的大伙普及一下。Springbootyml配置参数数据加密(数据加密篇......
  • springboot使用mybatis应用clickhouse
    一、clickhouse,说白了还是数据库,不一样的是clickhouse是列式存储,和传统的MySQL行式存储不同的地方在于,查询和所储。1)查询,行式和列式的区别,图形说明说明:理解上来说,行式对于一条数据的完整性索引会更快。而列式对于统计和查询指定数据会更加块。2)数据......
  • Springboot提高
    全局异常处理器未做处理的情况:当我没没有做任何异常处理时,mapper接口操作数据库出错时,会将异常向上抛给ServiceService中的异常会往上抛给controllercontroller会将异常抛给框架响应给浏览器一个JSON格式的数据这个数据并不符合我们统一响应结果的规范如何处理?方案一:......
  • Java__SpringBoot与Vue连接
    SpringBoot与Vue注解RequestMapping("/dir/")创建一个方便前端调用的接口目录/接口函数,前端可以获取到函数返回的数据@RestController@RequestMapping("/dir/")publicclassBotInfoController{@RequestMapping("getinfo/")publicMap<String,String>GetI......
  • SpringBoot 集成 Quartz + MySQL
    Quartz简单使用JavaSpringBoot中,动态执行bean对象中的方法源代码地址=>https://gitee.com/VipSoft/VipBoot/tree/develop/vipsoft-quartz工作原理解读只要配置好DataSourceQuartz会自动进行表的数据操作,添加QuartzJob任务保存QRTZ_JOB_DETAILS、QRTZ_TRIGGERS=>QR......
  • Java SpringBoot 7z 压缩、解压
    JavaSpringBoot7z压缩、解压JavaSpringBoot7z压缩、解压cmd7z文件压缩7z压缩测试添加依赖<dependency><groupId>org.apache.commons</groupId><artifactId>commons-compress</artifactId><version>1.12</versi......
  • 若依jwt
    Authorization:BearereyJhbGciOiJIUzUxMiJ9.eyJsb2dpbl91c2VyX2tleSI6ImRjMDRhOWE2LWE2YTgtNDA1My04MmU4LTRmNmRkMjdjYTA3NCJ9.8ZaOBAnKZ2acfBqZcHvsdRL9DYTaKxeGuyDUglt74HfMuw918p7mdj_uwyeKxA3xMcxi5WNKTOlda33xJ2mX3Alogin_tokens:dc04a9a6-a6a8-4053-82e8-4f6dd27ca07......
  • SpringBoot中底层对 /health 的请求是怎么处理的?
     在SpringBoot应用程序中,/health端点是通过HealthEndpointbean来处理的。当您访问/health端点时,SpringBoot会调用HealthEndpointbean的health()方法来检查应用程序的健康状态,并返回相应的响应。HealthEndpointbean是通过HealthEndpointAutoConfiguration自......
  • 配置Swagger带token的三种方式
    现在的项目基本上都是前后端分离,很多API的调用都需要用到token验证,本文就介绍怎么在swagger的header中自动添加token。在每个接口上手动添加headerpackagecom.morris.swagger.web;importcom.morris.swagger.vo.R;importio.swagger.annotations.Api;importio.swagger.annota......
  • 记录一次艰难的云服务器部署前后端项目springBoot+mybatis和vue(两天解决的前后端跨域
    前言大家好我是歌谣今天继续给大家带来后端java的学习最近刚学习完java的一个增删改查紧接着就是部署项目了代码准备工作前端:vue后端:springboot+mybatis数据库mysql部署后端项目打包找到maven-package-runmavenbuild云服务器上面建立文件mkdir/www/springBoot创建文件......