为什么要告别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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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;
}
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51

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加密生成token
String 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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

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();
} }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73

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>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

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");
}
}

spring集成jwt验证方式,token验证的更多相关文章

  1. 【JWT】JWT+HA256加密 Token验证

    目录 Token验证 传统的Token验证 JWT+HA256验证 回到顶部 Token验证 最近了解下基于 Token 的身份验证,跟大伙分享下.很多大型网站也都在用,比如 Facebook,Twi ...

  2. js函数验证方式:验证是否是数字,支持小数,负数

    验证 datatype="/^\d+(\.\d+)?$/" validatform验证是否是数字 支持小数点 datatype="d" 貌似支持小数 js函数验 ...

  3. 基于JAVA JWT 实现OATUH TOKEN验证

    什么是jwt? 最详细的是官网:https://jwt.io/ 这里以java的ssm框架为例,集成jwt. 1.pom.xml 导入jwt的包 <!-- jwt --> <!-- ...

  4. 如何在SpringBoot中集成JWT(JSON Web Token)鉴权

    这篇博客主要是简单介绍了一下什么是JWT,以及如何在Spring Boot项目中使用JWT(JSON Web Token). 1.关于JWT 1.1 什么是JWT 老生常谈的开头,我们要用这样一种工具 ...

  5. Spring集成Mybatis(Dao方式开发)

    Spring整成Mybatis注意事项:  1. 关键jar包不能少 2.可以单独整理好Mybatis框架,测试无误再集成Spring 3.集成时,参数级别的细节可以选择忽略,但思路必须清晰 代码如下 ...

  6. spring boot 2 集成JWT实现api接口认证

    JSON Web Token(JWT)是目前流行的跨域身份验证解决方案.官网:https://jwt.io/本文使用spring boot 2 集成JWT实现api接口验证. 一.JWT的数据结构 J ...

  7. 简易 Token 验证的实现

    简易 Token 验证的实现 前言 在我们的服务器和客户端的交互中,由于我们的业务中使用 RESTful API 的形式和客户端交互,而 API 又是无状态的,无法帮助我们识别这一次和上一次的请求由谁 ...

  8. Node教程——封装一个token验证器

    重要说明 这个轮子是 使用 express@5.0 + MongoDB构建起来的一个 node后台通用的验证器,里面主要讲的就是使用jwt,token进行验证,当然你想使用session也没问题,但是 ...

  9. Unit08: Spring集成mybatis

    Unit08: Spring集成mybatis 1. Spring集成mybatis (1)方式一 step1. 导包. spring-webmvc,mybatis,mybatis-spring, o ...

随机推荐

  1. (ScrollViewer或者有滚动条的控件)嵌套一个(ScrollViewer或者有滚动条的控件)禁用里面的滚动条

    转自:http://blog.csdn.net/haylhf/article/details/8351203 后有改动 在C# 中,两个ScrollViewer嵌套在一起或者ScrollViewer里 ...

  2. [转] Understanding-LSTMs 理解LSTM

    图文并茂,讲得极清晰. 原文:http://colah.github.io/posts/2015-08-Understanding-LSTMs/ colah's blog Blog About Con ...

  3. 关于python中的矩阵乘法(array和mat类型)

    关于python中的矩阵乘法,我们一般有两种数据格式可以实现:np.array()类型和np.mat()类型: 对于这两种数据类型均有三种操作方式: (1)乘号 * (2)np.dot() (3)np ...

  4. Java的static类

    首先Java的static类只能是静态内部类.如果在外部类声明为static,程序会编译通不过. 其次,主要了解下static内部类与普通内部类的区别是什么,以及static内部类的作用是什么,详见下 ...

  5. js学习笔记--基础部分

    自增 自增 ++ 通过自增可以使变量在自身的基础上增加1 对于一个变量自增以后,原变量的值会立即自增1 无论使a++, 还是++a,都会立即使原变量的值自增1. 不同的是a++ 和++a的值不同. a ...

  6. mongodb 创建更新语法

    创建文档 向MongoDB插入数据,使用insert, 如:db.refactor.insert({"refactor's blog":"http://www.cnblo ...

  7. 如何确定windows启动类型是bios还是uefi

    原文地址:http://www.kqidong.com/bios/3728.html 如何确定windows启动类型是bios还是uefi?随着装机越来越简单,大家对安装系统充满信心,但是了解到启动类 ...

  8. <第一站>人生的第一个博客

    在畅畅的疯狂暗示下(“最好”建个博客),我决定在博客园开通我的博客,在此记入我从3月23起的所学所想.在他的提醒之前,我曾经断断续续的在日记本上,手机备忘录里记录过我的学习情况和心路历程,总的来说,自 ...

  9. Chromium Embedded Framework (CEF)_3.2171.2069_v20170606_x86.tar.xz

    CEF 为观看各个直播平台而特此修改的浏览器 可以单独提取 Flash 视频, 并可以修改视频的大小等功能 [增加了960x90% 和 1280x90%] 这次修改是主要针对 YY web 直播平台 ...

  10. [转]POI大数据量Excel解决方案

    全文转载自:jinshuaiwang的博客 目前处理Excel的开源javaAPI主要有两种,一是Jxl(Java Excel API),Jxl只支持Excel2003以下的版本.另外一种是Apach ...