一、准备

  1. 依赖
<!--jwt依赖--><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>3.4.0</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-api</artifactId><version>0.10.7</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-impl</artifactId><version>0.10.7</version></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt-jackson</artifactId><version>0.10.7</version></dependency>
  1. 使用Md5工具对数据库密码加密
@Slf4j
public class Md5Utils {public static String getMD5String(String str) {try {// 生成一个MD5加密计算摘要MessageDigest md = MessageDigest.getInstance("MD5");// 计算md5函数md.update(str.getBytes());// digest()最后确定返回md5 hash值,返回值为8位字符串。因为md5 hash值是16位的hex值,实际上就是8位的字符// BigInteger函数则将8位的字符串转换成16位hex值,用字符串来表示;得到字符串形式的hash值//一个byte是八位二进制,也就是2位十六进制字符(2的8次方等于16的2次方)return new BigInteger(1, md.digest()).toString(16);} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("{}计算md5异常:{}",stackTraceElement,e.getMessage());return null;}}}
  1. 生成rsa的私钥和公钥,可以在线生成,不要空格不要换行,不要其他的字符
  2. 从数据库获取用户名和使用md5加密的密码
使用redis存储token,并且一个用户只允许有一个token
@Overridepublic ResultVo login(ManagerDto managerDto) {if (ObjectUtils.isEmpty(managerDto)){return new ResultVo().failure(ResultCode.PARAMETER_INVALID);}try {String userName = managerDto.getUserName();String password = managerDto.getPassword();IdleManagerEntity manager = managerMapper.getManager(userName);if (manager == null){log.info("用户名为空");return new ResultVo().failure(ResultCode.USER_NULL);}String md5String = Md5Utils.getMD5String(password);if (!md5String.equals(manager.getMd5Password())){log.info("密码错误");return new ResultVo().failure(ResultCode.PASSWORD_ERROR);}manager.setMd5Password("");try {String effective = tokenEffectiveUtils.isEffective(userName);// 获取私钥ClassPathResource classPathResource = new ClassPathResource("rsa_pri");InputStream inputStream = classPathResource.getInputStream();PrivateKey privateKey = RsaUtils.getPrivateKey(ResourceStream.readBytes3(inputStream));// 生成tokenString token = JwtUtils.generateTokenExpireInMinutes(manager, privateKey, timeOut);if (StringUtils.isBlank(effective)){redisUtils.set(userName,token,timeOut);log.info("{} create new token : {},timeout:{} min",userName,token,timeOut);}else {redisUtils.delete(userName);redisUtils.set(userName,token,timeOut);log.info("{} update token:{},timeOut:{} min",userName,token,timeOut);}log.info(" {} already login",userName);return new ResultVo().success(token);} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("{} token error:{}",stackTraceElement,e.getMessage());return new ResultVo().failure(ResultCode.SYSTEM_ERROR);}} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("登录异常");return new ResultVo().failure(ResultCode.SYSTEM_ERROR);}}

二、需要对请求方法进行拦截,判断是否携带token或者是否过期

  • 后端登录拦截
从redis中获取token,判断当前携带的token是否与redis的token相同
package com.idle.idlemanager.config;import com.idle.idlemanager.entity.dataobject.IdleManagerEntity;
import com.idle.idlemanager.enums.ResultCode;
import com.idle.idlemanager.util.JwtUtils;
import com.idle.idlemanager.util.RsaUtils;
import com.idle.idlemanager.util.TokenEffectiveUtils;
import com.idle.idlemanager.vo.ResultVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.ResourceUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.servlet.HandlerInterceptor;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.PublicKey;/*** @Description:* @date: 2022/3/11 17:37* @author: towards* @since JDK 1.8*/
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {@Autowiredprivate TokenEffectiveUtils tokenEffectiveUtils;@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response, Object handler) throws Exception {//放行请求方法为OPTIONS的请求String method = request.getMethod();if(method.equals("OPTIONS")){return  true;}//获取请求头中的请求信息String token = request.getHeader("token");//使用公钥解密进行校验//获取公钥PublicKey publicKey = RsaUtils.getPublicKey(ResourceUtils.getFile("src/main/resources/rsa_pub").getPath());try {IdleManagerEntity manager = (IdleManagerEntity) JwtUtils.getInfoFromToken(token, publicKey, IdleManagerEntity.class);if (!token.equals(tokenEffectiveUtils.isEffective(manager.getUserName()))){response.sendRedirect(request.getContextPath()+"/result");return false;}return true;}catch (Exception e){StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("{}token error:{}",stackTraceElement,e.getMessage());}//失败要响应json数据给前端response.sendRedirect(request.getContextPath()+"/result");return false;}}
  • 后端响应错误信息
@RequestMapping("result")public ResultVo result(){return new ResultVo().failure(ResultCode.TOKEN_OVERDUE);}

三、需要将拦截器注册到springmvc中,放行登录请求

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Autowiredprivate LoginInterceptor loginInterceptor;/*** 注册拦截器* @param registry*/@Overridepublic void addInterceptors(InterceptorRegistry registry) {/*** addInterceptor 注册拦截器* addPathPatterns 配置拦截规则*/registry.addInterceptor(loginInterceptor).excludePathPatterns("/login").addPathPatterns("/**");}
}

四、前端配置拦截器

  • 配置请求拦截器,为每一次请求添加token
//请求拦截器
service.interceptors.request.use(config => {config.headers.token = sessionStorage.getItem("token");return config}
)
  • 配置响应拦截器,根据后端“result”返回的错误信息验证token是否过期
// response interceptor  axios响应拦截器
service.interceptors.response.use(response => {if(response.data.code == 'A0004'){sessionStorage.removeItem("token")location.href = '/login'return ;}return response.data}
)

五、贴上公钥私钥吧

  • 私钥,rsa_pri
MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDXmLKFi9QRf7srERtx6VUQMJsswm+AFnxyZr8eYpm4/8VdIT345eqXeo/H9Jk6ZTkOjqDjGSt/CoHW2X/ZlnGSVqF03aMYgUMBw3MTcbMOEyyROLVWNHVhNXX1SIJPtl6/J0g/7phC0p3GnAqoxet/lEqK+G6lO4ShEiiDeN3PUjsFDt72MVguKVLvILJ0jB/i+Xk+xY89pFafJp51yAN3MTiKP++A0OYjrt9JrrIHc3LLnPOmyrfu88ppUbQc+JX5UVlzY96FrvNHgV4BpgISP9cAkT5URXB6UlPU7ji1h9c2mHTZp0yWGC9rM+dT/Wu1uwYQArhjaS/2G1LZ3wDfAgMBAAECggEBAKfKal3vJjv8OfHZnY949j/kZFBgfqCkX3Q1rNZ8DIFjZfoGDhIw9fOwakhHgB1nfBFtRZ+ZDjYQOl645Xy1TmyCyaOHfxBqQXkU4PGoEp+Ioq3fAZo2t4fRMJ2WMfzRxUllzCAdlBiljC9vcAhMCO1AvwcLNCmaea1V0XwIzDA1s9C+xcmTUupSMATxyKYM9cRf5EW6tYuQTHFTRmvl6f2Ge9SfQRGZx0QC1HCQ1WwejT3QKIB4sk7i933fP54EcbUwNL+S9kr/Z7xHKiXkyPeFfBBZfi1mKOr+tQhwsnisauLk60j//KgW07ivS5fVYvm/42j4D/+WMO3unoSrhkECgYEA+qGakiCEY+WW+CwSVAHy6dmZQLAa/lkSJKaMRYbUb1xcEcEAUdrRjHiw1RePmFVlzpfPkay8u19GS4WMbOIQREGqMgEeVef3pVTVm/PGxEqVHom3l9kqKI0N5tJihJpWoKrfybP2nIPfA7neEYRdI2ZH5qeIx2yRnG4Rac3cWmECgYEA3Db40TJxgBZ0jzIrmOf3qq8osjuLd1bTtvbps21ceoZzO1bAg2YwsaEGHkucuVBNFhRJBaRXmmEfwQHhsGJfW+SaxbH3NLygETu4OneuK43TBrFqW9tyYZBOG4itjEHyBQP9ijotRiRx/4B5X8kvyjwIC0g8dlgOcAplv3O5oz8CgYBmHKNKN99Yh/jbQbFx8p1Sc2pB9b35tLZ0ojpyNT2l5V5JiXWk498OOTnqh7/kU5637hgOhO8b8/RC3rVYwz3XYV2DI/uFCo5WGNsyv75SyQQ6PefEASFxBg8M5NhoqCz1Jskod57ZI80fyoFUZ7Y+rvRKYCWVAoHM1vdXQR0u4QKBgQCaAZPncbiw1IN1taeJywiJBPCYHU5/CmkL9wgfpKbdRXQHFreR7YC2aR+HRmf3rbILc+pRmMpvO+diKre0jEeWU3zuL3TsG9Jx2usPcK2M5iWj86WnUgRfOPV3ChIdGe1xFoZVCjSpbkmPX0EC/QeADpWtljo6pYCLWKopx3wXLwKBgQDIEfOiQVVsq8F/T5Ja7ut0D96llXRjDFRT2gQ9gAh/bGmfesEweeAt3yrYtEwOk0i7whhfLiXYLZjCIe+EjVDbvxHGvQ1Xj7uvvIqzzboQ6lmcM6+VIqIIGxm4hS/uz5ul6gI48CB7k/1dKSZowiQkTA1I5DMyl4ZqWflP34dIxg==
  • 公钥,rsa_pub
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA15iyhYvUEX+7KxEbcelVEDCbLMJvgBZ8cma/HmKZuP/FXSE9+OXql3qPx/SZOmU5Do6g4xkrfwqB1tl/2ZZxklahdN2jGIFDAcNzE3GzDhMskTi1VjR1YTV19UiCT7ZevydIP+6YQtKdxpwKqMXrf5RKivhupTuEoRIog3jdz1I7BQ7e9jFYLilS7yCydIwf4vl5PsWPPaRWnyaedcgDdzE4ij/vgNDmI67fSa6yB3Nyy5zzpsq37vPKaVG0HPiV+VFZc2Peha7zR4FeAaYCEj/XAJE+VEVwelJT1O44tYfXNph02adMlhgvazPnU/1rtbsGEAK4Y2kv9htS2d8A3wIDAQAB

六、redis工具类

package com.idle.idlemanager.util;import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;import java.util.concurrent.TimeUnit;/*** redis操作工具类.</br>* (基于RedisTemplate)* @author xcbeyond* 2018年7月19日下午2:56:24*/
@Slf4j
@Component
public class RedisUtils {@Autowiredprivate RedisTemplate<String, String> redisTemplate;/*** 读取缓存* * @param key* @return*/public String get(final String key) {return redisTemplate.opsForValue().get(key);}/*** 写入缓存*/public boolean set(final String key, String value,Integer timeOut) {boolean result = false;try {redisTemplate.opsForValue().set(key, value,timeOut, TimeUnit.MINUTES);result = true;} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("{} redis set error:{}",stackTraceElement,e.getMessage());}return result;}/*** 更新缓存*/public boolean getAndSet(final String key, String value) {boolean result = false;try {redisTemplate.opsForValue().getAndSet(key, value);result = true;} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("redis update error",stackTraceElement,e.getMessage());}return result;}/*** 删除缓存*/public boolean delete(final String key) {boolean result = false;try {redisTemplate.delete(key);result = true;} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("redis delete error",stackTraceElement,e.getMessage());}return result;}
}

七、判断当前用户是否过期

package com.idle.idlemanager.util;import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;/*** author:towards* date:2022/3/26 13:13* discribe: 判断用户token是否过期!*/
@Slf4j
@Component
public class TokenEffectiveUtils {@Autowiredprivate RedisUtils redisUtils;/***  判断当前用户名的token是否过期* @param managerName 管理员名字* @return*/public String isEffective(String managerName){String s = "";try {s = redisUtils.get(managerName);} catch (Exception e) {StackTraceElement stackTraceElement = e.getStackTrace()[0];log.error("{} judge managermanent token effective error:{}",stackTraceElement,e.getMessage());}return s;}
}

使用Jwt验证登录demo相关推荐

  1. 用户修改了信息jwt服务器怎么识别,jwt验证登录信息

    为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...

  2. 秒滴云短信验证登录小demo

    短信验证登录demo <a class="click_login_head" data-href="/member" data-method=" ...

  3. Vue项目使用拦截器和JWT验证 完整案例

    挺详细的一个案例项目,值得参考! 作者:YXi https://juejin.im/post/6844903959883218951) https://gitee.com/gitee_fanjunya ...

  4. java jwt 验证_教程:用Java创建和验证JWT

    java jwt 验证 "我喜欢编写身份验证和授权代码." 〜从来没有Java开发人员. 厌倦了一次又一次地建立相同的登录屏幕? 尝试使用Okta API进行托管身份验证,授权和多 ...

  5. SQL Server之 (四) ADO增删查改 登录demo 带参数的sql语句 插入自动返回行号

    SQL Server之 (四) ADO增删查改  登录demo  带参数的sql语句  插入自动返回行号 自己学习笔记,转载请注明出处,谢谢!---酸菜 1.什么是ADO.NET ADO.NET是一组 ...

  6. 本地ASP.NET开发页面使用AzureAD(AAD)验证登录

    Azure和Office365已不是一个热门话题了,因为所谓的云时代已经走进了技术大师们的内心,大家多少有一定了解了,所以就不多介绍了,我的Blog中之前也写了很多关于Azure及Office365的 ...

  7. 使用token验证登录信息,把token存到数据库中

    使用token验证登录信息,把生成的token存到数据库中,根据用户id判断是否重复登录,重复登录就重置到期时间 调用登录接口返回出token和uuid信息 每次访问都需要在Headers里面添加该数 ...

  8. 登陆模块之JWT单点登录

    功能描述:通过一次登录来实现多个模块之间来回跳转,数据同步 单点登录的实现方式 redis实现session共享 jwt单点登录 cas单点登录 买单点登录服务器 本篇博客着重讲解JWT单点登录 首先 ...

  9. Vue与Node.js实现手机短信验证登录

    手机短信使用的第三方平台是联容云,注册就送8块钱体验费,足够自己用用了,注册完自己建一个应用就能拿到需要使用的配置了,如图 注册完之后1就可以使用了. Node.js后端使用了Express框架 &q ...

最新文章

  1. 山石网科-Hillstone-IPsec V_P_N常见故障debug排错心得终结版
  2. golang runes 字符串 互转
  3. boost::mpl模块实现inherit相关的测试程序
  4. 纯虚函数竟然可以有实现体(但无任何实用价值,声明成普通虚函数就可以了)
  5. 牛客假日团队赛5 L Catch That Cow HDU 2717 (BFS)
  6. c ++查找字符串_C ++类和对象| 查找输出程序| 套装4
  7. linux 多线程并行计算,浅谈.NET下的多线程和并行计算(五)线程池基础上
  8. 【译】使用 CocoaPods 模块化iOS应用
  9. 开源项目ActiveAndroid简述增、删、改、查
  10. 用Delphi内联汇编获取机器码
  11. 汉宁窗+matlab,m汉宁窗hanning汉明窗hamming矩形窗-read.ppt
  12. Scratch互动编程手柄兼容mblock网易卡搭慧编程猫Mind+ 编程键盘手柄20210223
  13. easyui1.5:combobox:onSelect
  14. python中将字符变为大写_python3.4.3将汉字转换为大写拼音首字母
  15. Win11怎么不让软件联网?Win11禁止某个软件联网的方法
  16. win11怎么装回win10系统
  17. RK3399平台开发系列讲解(内核驱动外设篇)6.17、VOP驱动解析
  18. 人脸识别方案(包含tcp ,http,socket 三者的区别)
  19. No.053<软考>《(高项)备考大全》【冲刺7】《软考之 119个工具 (5)》
  20. The authenticity of host xxx can‘t be established 错误

热门文章

  1. 【网页图标】favicon.ico文件的设置
  2. 西南大学907专硕考研,西南大学计算机808学硕
  3. scala的两种变量类型 var 和 val
  4. 360应用宝上架流程及所需材料
  5. 精简《JavaScript高级程序设计》五、引用类型(上)
  6. UEStudio/UltraEdit 的语法高亮文件 (*.uew)
  7. kafka按照时间查询记录
  8. js购物车功能php,使用JS实现购物车功能步骤详解
  9. ios上查看html源码,如何在ios手机端的Safari浏览器中“查看网页源代码”
  10. 申宝证券-市场呈现出震荡分化走势