为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录),当然解决办法有,可以用spring-session。如果该系统同时为移动端服务呢?移动端通过url向后台要数据,如果用session,通过sessionId识别用户,万一sessionId被截获了,别人可以利用sessionId向后台要数据,就有安全隐患了。所以有必要跟session说拜拜了。服务端不需要存储任何用户的信息,用户的验证应该放在客户端,jwt就是这种方式!

什么是jwt?

最详细的是官网:https://jwt.io/

这里以java的ssm框架为例,集成jwt。

1.pom.xml 导入jwt的包

 <!-- jwt --><!-- https://mvnrepository.com/artifact/com.auth0/java-jwt --><dependency><groupId>com.auth0</groupId><artifactId>java-jwt</artifactId><version>2.2.0</version></dependency>

2.编写jwt的工具类,有加密解密功能就好

import com.auth0.jwt.JWTSigner;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.internal.com.fasterxml.jackson.databind.ObjectMapper;import java.util.HashMap;
import java.util.Map;public class JWT {private static final String SECRET = "XX#$%()(#*!()!KL<><MQLMNQNQJQK sdfkjsdrow32234545fdf>?N<:{LWPW";private static final String EXP = "exp";private static final String PAYLOAD = "payload";//加密,传入一个对象和有效期public static <T> String sign(T object, long maxAge) {try {final JWTSigner signer = new JWTSigner(SECRET);final Map<String, Object> claims = new HashMap<String, Object>();ObjectMapper mapper = new ObjectMapper();String jsonString = mapper.writeValueAsString(object);claims.put(PAYLOAD, jsonString);claims.put(EXP, System.currentTimeMillis() + maxAge);return signer.sign(claims);} catch(Exception e) {return null;}}//解密,传入一个加密后的token字符串和解密后的类型public static<T> T unsign(String jwt, Class<T> classT) {final JWTVerifier verifier = new JWTVerifier(SECRET);try {final Map<String,Object> claims= verifier.verify(jwt);if (claims.containsKey(EXP) && claims.containsKey(PAYLOAD)) {long exp = (Long)claims.get(EXP);long currentTimeMillis = System.currentTimeMillis();if (exp > currentTimeMillis) {String json = (String)claims.get(PAYLOAD);ObjectMapper objectMapper = new ObjectMapper();return objectMapper.readValue(json, classT);}}return null;} catch (Exception e) {return null;}}}

3.jwt有了,ssm要如何去利用,用户验证的第一步是登录,登录时根据用户传来的username和password到数据库验证身份,如果合法,便给该用户jwt加密生成token

//处理登录@RequestMapping(value="login", produces = "application/json; charset=utf-8")public @ResponseBody ResponseData login(HttpServletRequest request, @RequestParam( "email") String email,@RequestParam("password") String password) {Login login = new Login();login.setEmail(email);login.setPassword(password);ResponseData responseData = ResponseData.ok();//先到数据库验证Integer loginId = userService.checkLogin(login);if(null != loginId) {User user = userService.getUserByLoginId(loginId);login.setId(loginId);//给用户jwt加密生成tokenString token = JWT.sign(login, 60L* 1000L* 30L);//封装成对象返回给客户端responseData.putDataValue("loginId", login.getId());responseData.putDataValue("token", token);responseData.putDataValue("user", user);}else{responseData =  ResponseData.customerError();}   return responseData;}

4.在用户登录时,把loginId和token返回给前台,以后用户每次请求时,都得带上这两个参数,后台拿到token后解密出loginId,与用户传递过来的loginId比较,如果相同,则说明用户身份合法。因为是每个登录过后的每个请求,这里用springmvc的拦截器做

<mvc:interceptors>    <mvc:interceptor>    <!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->  <mvc:mapping path="/**" />  <!-- /register 和 /login 不需要拦截-->  <mvc:exclude-mapping path="/register" /><mvc:exclude-mapping path="/login" /><bean class="com.xforce.charles.interceptor.TokenInterceptor"></bean>    </mvc:interceptor>  <!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的postHandle和afterCompletion方法 -->  </mvc:interceptors> 

5.拦截器代码

import java.io.PrintWriter;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import com.alibaba.fastjson.JSONObject;
import com.xforce.charles.model.Admin;
import com.xforce.charles.model.Login;
import com.xforce.charles.util.JWT;
import com.xforce.charles.util.ResponseData;public class TokenInterceptor implements HandlerInterceptor{public void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception arg3)throws Exception {}public void postHandle(HttpServletRequest request, HttpServletResponse response,Object handler, ModelAndView model) throws Exception {}//拦截每个请求public boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception {response.setCharacterEncoding("utf-8");String token = request.getParameter("token");ResponseData responseData = ResponseData.ok();//token不存在if(null != token) {Login login = JWT.unsign(token, Login.class);String loginId = request.getParameter("loginId");//解密token后的loginId与用户传来的loginId不一致,一般都是token过期if(null != loginId && null != login) {if(Integer.parseInt(loginId) == login.getId()) {return true;}else{responseData = ResponseData.forbidden();responseMessage(response, response.getWriter(), responseData);return false;}}else{responseData = ResponseData.forbidden();responseMessage(response, response.getWriter(), responseData);return false;}}else{responseData = ResponseData.forbidden();responseMessage(response, response.getWriter(), responseData);return false;}}//请求不通过,返回错误信息给客户端private void responseMessage(HttpServletResponse response, PrintWriter out, ResponseData responseData) {responseData = ResponseData.forbidden();response.setContentType("application/json; charset=utf-8");  String json = JSONObject.toJSONString(responseData);out.print(json);out.flush();out.close();}}

6.注意点:用@ResponseBody返回json数据时,有时会有乱码,需要在springmvc的配置文件里面加以下配置(spring4以上)

<mvc:annotation-driven><mvc:message-converters register-defaults="true"><bean class="org.springframework.http.converter.StringHttpMessageConverter"><property name="supportedMediaTypes" value = "text/plain;charset=UTF-8" /></bean></mvc:message-converters></mvc:annotation-driven>  

7.最后分享一个类,用于返回给客户端的万能类,我觉得它可以满足一般的接口

import java.util.HashMap;
import java.util.Map;public class ResponseData {private final String message;private final int code;private final Map<String, Object> data = new HashMap<String, Object>();public String getMessage() {return message;}public int getCode() {return code;}public Map<String, Object> getData() {return data;}public ResponseData putDataValue(String key, Object value) {data.put(key, value);return this;}private ResponseData(int code, String message) {this.code = code;this.message = message;}public static ResponseData ok() {return new ResponseData(200, "Ok");}public static ResponseData notFound() {return new ResponseData(404, "Not Found");}public static ResponseData badRequest() {return new ResponseData(400, "Bad Request");}public static ResponseData forbidden() {return new ResponseData(403, "Forbidden");}public static ResponseData unauthorized() {return new ResponseData(401, "unauthorized");}public static ResponseData serverInternalError() {return new ResponseData(500, "Server Internal Error");}public static ResponseData customerError() {return new ResponseData(1001, "customer Error");}
}

告别session! spring 集成 jwt 验证方式相关推荐

  1. SpringMVC 集成 JWT验证方式

    JWT官网: https://jwt.io/ 这里以java的ssm框架为例,集成jwt. 1.pom.xml 导入jwt的包 <!-- jwt --> <dependency> ...

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

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

  3. windows集成身份验证

    集成windows身份验证 这种验证方式里面也分为两种情况 NTLM验证 这种验证方式需要把用户的用户名和密码传送到服务端,服务端验证用户名和密码是否和服务器的此用户的密码一致.用户名用明码传送,但是 ...

  4. Spring Security技术栈学习笔记(十四)使用Spring Social集成QQ登录验证方式

    上一篇文章<Spring Security技术栈开发企业级认证与授权(十三)Spring Social集成第三方登录验证开发流程介绍>主要是介绍了OAuth2协议的基本内容以及Spring ...

  5. Spring Boot+Spring Security+JWT 实现token验证

    Spring Boot+Spring Security+JWT 实现token验证 什么是JWT? JWT的工作流程 JWT的主要应用场景 JWT的结构 SpringBoot+Spring Secur ...

  6. Angular 6集成Spring Boot 2,Spring Security,JWT和CORS

    主要内容:Spring Boot 2的基础应用.CORS配置.Actuator监控:Spring Boot集成springfox-swagger,利用Swagger生成JSON API文档,利用Swa ...

  7. SpringBoot集成JWT实现Token登录验证

    目录 1.1 JWT是什么? 1.2 JWT主要使用场景 1.3 JWT请求流程 1.4 JWT结构 二,SpringBoot集成JWT具体实现过程 2.1添加相关依赖 2.2自定义跳出拦截器的注解 ...

  8. 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之二

    本篇承接上一篇,关于Session以及JWT Token参考: 前后端分离的用户验证原理及Spring Boot + JWT的框架搭建(附完整的框架代码)之一 框架整体描述 框架使用Spring Bo ...

  9. SpringBoot集成JWT实现token验证

    Jwt全称是:json web token,以JSON对象的形式安全的传递信息.它将用户信息加密到token里,服务器不保存任何用户信息.服务器通过使用保存的密钥验证token的正确性,只要正确即通过 ...

最新文章

  1. 基于Hyper-V3.0搭建XenDesktop7之九 部署虚拟应用之模板准备
  2. 向textarea元素输入限制长度的字符
  3. 使用DBUnit框架数据库插入特殊字符失败的查错经历
  4. win2000服务器 网站设置,服务器_Win2000中DNS服务器的设置,一、DNS概述 计算机在网 - phpStudy...
  5. 华为y7可以人脸识别吗_华为手机经常弹出“系统更新”提示,可以不更新吗?看完涨知识了...
  6. Lottie 站在巨人的肩膀上实现 Android 酷炫动画效果
  7. oracle 游标(学校)
  8. 启动mysq服务_mysql安装、启动
  9. cache控制器取值从TCM/CACHE/FLASH
  10. 17. 使用“swap技巧”除去多余得容量
  11. Atitit 提升科技影响力 目录 1. 大原则 2 1.1. 科技强人必须是创新型[ 2 1.2. 要有一定的体量和规模 2 2. 创新能力主要科技指标 2 2.1. 领域科技大奖与荣誉 2 2
  12. 子龙山人Learn Emacs in 21 Days: day 6 学习笔记
  13. STC12C5A60S2获取GPS信息(LCD1602显示)(一)
  14. 菜鸟教程python爬虫小说_Python 爬虫介绍 | 菜鸟教程
  15. sd卡驱动 android,sd卡驱动异常怎么办 sd卡驱动程序无法使用【详解】
  16. 30款常用的大数据分析工具推荐(最新)
  17. html里面<i>和<em>标签的区别
  18. 签名申请问题(100%成功)
  19. 广告投放的相关名词CPM/CPT/CPC/CPD/CPI/CPS
  20. Tekton之三:快速理解 Tekton 是如何工作的

热门文章

  1. vue中定时器一般用法,定时器函数传参以及清除定时器
  2. Python实践:画个动图玩玩,Python绘制GIF图总结
  3. eyoucms 网络公司易优专员介绍几种SEO工具
  4. 小鱼授权系统源码_无加密
  5. Python 循环语句和字符串内置函数
  6. 单向循环链表改成双向循环链表
  7. mysql skip用法_【MySql】sql_slave_skip_counter 参数的用法解析
  8. av_realloc
  9. 集成【支付宝】实现支付功能
  10. 【版本升级】Eclipse超强插件CodeMix发布v3.0