jwt验证登录信息
为什么要告别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加密生成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;
}
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");
}
}
jwt验证登录信息的更多相关文章
- Jwt验证登录
练习模板:https://gitee.com/zh1446802857/swagger-multi-version-api.git Jwt在我的 认知里,是一套门锁.别人(用户)需要用到你的接口 的时 ...
- 解决:使用ajax验证登录信息返回前端页面时,当前整个页面刷新。
源代码如下: function loginform(){ $.ajax({ url:"loginValidate.do", type:'post', data:{"nam ...
- 从壹开始前后端分离 [ Vue2.0+.NET Core2.1] 二十四║ Vuex + JWT 实现授权验证登录
壹周回顾 哈喽,又是元气满满的一个周一,又与大家见面了,周末就是团圆节了,正好咱们的前后端也要团圆了,为什么这么说呢,因为以后的开发可能就需要前后端一起了,两边也终于会师了,还有几天Vue系列就基本告 ...
- golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息
golang学习笔记10 beego api 用jwt验证auth2 token 获取解码信息 Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放 ...
- Python 解密JWT验证苹果登录
验证苹果登录,官方提供两种验证方法,一种是token,另一个种是code.这里使用的是token 登录流程: 苹果客户端调用苹果API,获取到用户的信息,包括: user_id 昵称 identity ...
- spring boot:spring security整合jwt实现登录和权限验证(spring boot 2.3.3)
一,为什么使用jwt? 1,什么是jwt? Json Web Token, 它是JSON风格的轻量级的授权和身份认证规范, 可以实现无状态.分布式的Web应用授权 2,jwt的官网: https:// ...
- Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven)
Spring 笔记 -06- 从 MySQL 建库到 登录验证数据库信息(maven) 本篇和 Spring 没有什么关系,只是学习 Spring,必备一些知识,所以放在这里了. 本篇内容: (1)M ...
- spring集成jwt验证方式,token验证
为什么要告别session?有这样一个场景,系统的数据量达到千万级,需要几台服务器部署,当一个用户在其中一台服务器登录后,用session保存其登录信息,其他服务器怎么知道该用户登录了?(单点登录), ...
- webapi中使用token验证(JWT验证)
本文介绍如何在webapi中使用JWT验证 准备 安装JWT安装包 System.IdentityModel.Tokens.Jwt 你的前端api登录请求的方法,参考 axios.get(" ...
随机推荐
- Bitset([HZOI 2015]偏序++)
Bitset简介 下面介绍C++ STL 中一个非常有用的东西: Bitset 类似于二进制状压,它可以把信息转化成一个01串存储起来 定义方法: 首先要#include<bitset>或 ...
- MongoDB存储引擎(中)——WiredTiger
上一篇博文介绍了MongoDB的MMAPv1存储引擎,本文接着介绍MongoDB另一个存储引擎--WiredTiger,WiredTiger是在MongoDB3.0版本引入的,并且在MongoDB3. ...
- js监听input输入框值的实时变化实例
情景:监听input输入框值的实时变化实例 解决方法:1.在元素上同时绑定oninput和onporpertychanger事件 实例:<script type="text/JavaS ...
- MySQL增量订阅&消费组件Canal POC
POC的目的:1.与MYSQL的对接方式,配置文档2.订阅的延迟3.订阅后宕机消息会不会丢失4.能不能从指定的点开始重新订阅5.高并发写入的时候,日志的顺序是否还能保持,不考虑消费的情况订阅是否会延迟 ...
- c++标准头文件
C++标准库的所有头文件都没有扩展名.C++标准库的内容总共在50个标准头文件中定义,其中18个提供了C库的功能. <cname>形式的标准头文件[ <complex>例外]其 ...
- vue使用 better-scroll的参数和方法
格式:var obj = new BScroll(object,{[option1,],.,.}); 注意: 1.要确保object元素的高度比其父元素高 2.使用时,一定要确保object所在的do ...
- Python3数据库模块(sqlite3,SQLite3)
一.sqlite命令 创建数据库:在控制台sqlite3 name .databases 查看数据库 .tables 查看表格名 databaseName .dump & ...
- Angular开发实践(一):环境准备及框架搭建
引言 在工作中引入Angular框架将近一年了,在这一年中不断的踩坑和填坑,当然也学习和积累了很多的知识,包括MVVM框架.前后端分离.前端工程化.SPA优化等等.因此想通过Angular开发实践这系 ...
- [Oracle] UNIX与Windows 2000上Oracle的差异(III)
作者:Ian Adam & David Stien, SAIC Ltd 日期:19-Dec-2003 出处:http://www.dbanotes.net翻译:Fenng ORACLE 的安装 ...
- NodeJs的async
async.auto最强大的一个api,它适合逻辑复杂的代码,代码中你一部分需要串行,两部分相互依赖,一部分又需要并行,代码中不需要依赖,这个时候你就可以通过auto随性所欲控制你的代码逻辑. var ...