layui登录后token问题
layui是一个非常简单且实用的后台管理系统搭建框架,里面的插件丰富使用简单,只需要在原有基础上进行修改即可,但是在数据处理方面略显薄弱,内置的jquery在实际过程中略显不足,若是能添加内置的mvc模式框架那就更好了
先介绍layui在登录这一块的使用,
登录问题主要是在token的存储调用上,先贴出后台的创建token以及拦截器的代码
首先引入jar包
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.7.0</version>
<exclusions>
<exclusion>
<artifactId>jackson-databind</artifactId>
<groupId>com.fasterxml.jackson.core</groupId>
</exclusion>
</exclusions>
</dependency>
token使用io.jsonwebtoken ,可以自定义秘钥,并存储登录信息
package com.zeus.utils; import cn.hutool.json.JSON;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.zeus.constant.CommonConstants;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.crypto.spec.SecretKeySpec; import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date; public class TokenUtil {
private static Logger LOG = LoggerFactory.getLogger(TokenUtil.class); /**
* 创建TOKEN
*
* @param id, issuer, subject, ttlMillis
* @return java.lang.String
* @methodName createJWT
* @author fusheng
* @date 2019/1/10
*/
public static String createJWT(String id, String issuer, String subject, long ttlMillis) { SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256; long nowMillis = System.currentTimeMillis();
Date now = new Date(nowMillis); byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary("englishlearningwebsite");
Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName()); JwtBuilder builder = Jwts.builder().setId(id)
.setIssuedAt(now)
.setSubject(subject)
.setIssuer(issuer)
.signWith(signatureAlgorithm, signingKey); if (ttlMillis >= 0) {
long expMillis = nowMillis + ttlMillis;
Date exp = new Date(expMillis);
builder.setExpiration(exp);
}
return builder.compact();
} /**
* 解密TOKEN
*
* @param jwt
* @return io.jsonwebtoken.Claims
* @methodName parseJWT
* @author fusheng
* @date 2019/1/10
*/
public static Claims parseJWT(String jwt) {
Claims claims = Jwts.parser()
.setSigningKey(DatatypeConverter.parseBase64Binary("englishlearningwebsite"))
.parseClaimsJws(jwt).getBody();
return claims;
} }
解密主要使用到 parseJWT 方法
public static Contact getContact(String token) {
Claims claims = null;
Contact contact = null;
if (token != null) {
//得到claims类
claims = TokenUtil.parseJWT(token);
cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(claims.getSubject());
contact = jsonObject.get("user", Contact.class);
}
return contact;
}
claims 中是解密后的token类,存储token中的全部信息
//解密token
claims = TokenUtil.parseJWT(token);
//得到用户的类型
String issuer = claims.getIssuer();
//得到登录的时间
Date issuedAt = claims.getIssuedAt();
//得到设置的登录id
String id = claims.getId();
//claims.getExpiration().getTime() > DateUtil.date().getTime() ,判断tokern是否过期
//得到存入token的对象
cn.hutool.json.JSONObject jsonObject = JSONUtil.parseObj(claims.getSubject());
Contact contact = jsonObject.get("user", Contact.class);
创建好的token会在页面中放置到请求头中,后台通过来拦截器来判断是否过期,若过期则拦截请求,成功则在响应头中返回新的token更新过期时间
package com.zeus.interceptor; import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import com.zeus.utils.TokenUtil;
import io.jsonwebtoken.Claims;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Map; import static com.zeus.constant.CommonConstants.EFFECTIVE_TIME; /**
* 登陆拦截器
*
* @author:fusheng
* @date:2019/1/10
* @ver:1.0
**/
public class LoginHandlerIntercepter implements HandlerInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(LoginHandlerIntercepter.class); /**
* token 校验
*
* @param httpServletRequest, httpServletResponse, o
* @return boolean
* @methodName preHandle
* @author fusheng
* @date 2019/1/3 0003
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
Map<String, String[]> mapIn = httpServletRequest.getParameterMap();
JSON jsonObject = JSONUtil.parseObj(mapIn);
StringBuffer stringBuffer = httpServletRequest.getRequestURL(); LOG.info("httpServletRequest ,路径:" + stringBuffer + ",入参:" + JSONUtil.toJsonStr(jsonObject)); //校验APP的登陆状态,如果token 没有过期
LOG.info("come in preHandle");
String oldToken = httpServletRequest.getHeader("token");
LOG.info("token:" + oldToken);
/*刷新token,有效期延长至一个月*/
if (StringUtils.isNotBlank(oldToken)) {
Claims claims = null;
try {
claims = TokenUtil.parseJWT(oldToken);
} catch (Exception e) {
e.printStackTrace();
String str = "{\"code\":801,\"msg\":\"登陆失效,请重新登录\"}";
dealErrorReturn(httpServletRequest, httpServletResponse, str);
return false;
}
if (claims.getExpiration().getTime() > DateUtil.date().getTime()) {
String userId = claims.getId();
try {
String newToken = TokenUtil.createJWT(claims.getId(), claims.getIssuer(), claims.getSubject(), EFFECTIVE_TIME);
LOG.info("new TOKEN:{}", newToken);
httpServletRequest.setAttribute("userId", userId);
httpServletResponse.setHeader("token", newToken);
LOG.info("flush token success ,{}", oldToken);
return true;
} catch (Exception e) {
e.printStackTrace();
String str = "{\"code\":801,\"msg\":\"登陆失效,请重新登录\"}";
dealErrorReturn(httpServletRequest, httpServletResponse, str);
return false;
}
}
}
String str = "{\"code\":801,\"msg\":\"登陆失效,请重新登录\"}";
dealErrorReturn(httpServletRequest, httpServletResponse, str);
return false;
} @Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
} @Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
} /**
* 返回错误信息给WEB
*
* @param httpServletRequest, httpServletResponse, obj
* @return void
* @methodName dealErrorReturn
* @author fusheng
* @date 2019/1/3 0003
*/
public void dealErrorReturn(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object obj) {
String json = (String) obj;
PrintWriter writer = null;
httpServletResponse.setCharacterEncoding("UTF-8");
httpServletResponse.setContentType("application/json; charset=utf-8");
try {
writer = httpServletResponse.getWriter();
writer.print(json); } catch (IOException ex) {
LOG.error("response error", ex);
} finally {
if (writer != null) {
writer.close();
}
}
}
}
讲完了token ,再讲layui如何存储token,并在每次渲染时添加token到请求头中
form.on('submit(LAY-user-login-submit)', function (obj) {
//请求登入接口
admin.req({
//实际使用请改成服务端真实接口
url: '/userInfo/login',
method: 'POST',
data: obj.field,
done: function (res) {
if (res.code === 0) {
//请求成功后,写入 access_token
layui.data(setter.tableName, {
key: "token",
value: res.data.token
});
//登入成功的提示与跳转
layer.msg(res.msg, {
offset: '15px',
icon: 1,
time: 1000
}, function () {
location.href ="index"
});
} else {
layer.msg(res.msg, {
offset: '15px',
icon: 1,
time: 1000
});
}
}
});
});
我们将返回的token信息存入layui本地存储的表中,在config.js中会配置表名,一般直接使用layui.setter.tableName 即可,
由于layui的table 是通过js渲染的,我们无法在js中对它进行设置请求头,而且每一个表格都要配置极为麻烦,但layui的数据表格是基于ajax请求的,所以我们选在在layui的module中手动修改table.js使得,每次请求是都会自动携带请求头
a.contentType && 0 == a.contentType.indexOf("application/json") && (d = JSON.stringify(d)), t.ajax({
type: a.method || "get",
url: a.url,
contentType: a.contentType,
data: d,
dataType: "json",
headers: {"token":layui.data(layui.setter.tableName)['token']},
success: function (t) {
if(t.code==801){
top.location.href = "index";
}else {
"function" == typeof a.parseData && (t = a.parseData(t) || t), t[n.statusName] != n.statusCode ? (i.renderForm(), i.layMain.html('<div class="' + f + '">' + (t[n.msgName] || "返回的数据不符合规范,正确的成功状态码 (" + n.statusName + ") 应为:" + n.statusCode) + "</div>")) : (i.renderData(t, e, t[n.countName]), o(), a.time = (new Date).getTime() - i.startTime + " ms"), i.setColsWidth(), "function" == typeof a.done && a.done(t, e, t[n.countName])
}
},
error: function (e, t) {
i.layMain.html('<div class="' + f + '">数据接口请求异常:' + t + "</div>"), i.renderForm(), i.setColsWidth()
},
complete: function( xhr,data ){
layui.data(layui.setter.tableName, {
key: "token",
value: xhr.getResponseHeader("token")==null?layui.data(layui.setter.tableName)['token']:xhr.getResponseHeader("token")
})
}
})
在table.js中找到这一代码,按上面的配置
headers: {"token":layui.data(layui.setter.tableName)['token']},这里是设置请求头的token,拿到登录成功后存储在表中的layui.data(layui.setter.tableName)['token'], 这样既可携带token很简单
同时我们需要更新token的过期时间,那么就要拿到新的token,并放入表中
complete: function( xhr,data ){
layui.data(layui.setter.tableName, {
key: "token",
value: xhr.getResponseHeader("token")==null?layui.data(layui.setter.tableName)['token']:xhr.getResponseHeader("token") })
}
使用ajax的complete方法拿到token,并覆盖表的旧token,如果为空则不覆盖
table讲完,来看看请求,layui中内置了jquery,可以使用var $ = layui,jquery, 来使用内置的ajax,那么我们也需要对ajax进行配置
pe.extend({
active: 0,
lastModified: {},
etag: {},
ajaxSettings: {
url: en,
type: "GET",
isLocal: Vt.test(tn[1]),
global: !0,
processData: !0,
async: !0,
headers: {"token":layui.data(layui.setter.tableName)['token']},
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
accepts: {
"*": Zt,
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript"
},
contents: {xml: /\bxml\b/, html: /\bhtml/, json: /\bjson\b/},
responseFields: {xml: "responseXML", text: "responseText", json: "responseJSON"},
converters: {"* text": String, "text html": !0, "text json": pe.parseJSON, "text xml": pe.parseXML},
flatOptions: {url: !0, context: !0}
},
同样在l你引用的ayui.js或者layui.all.js中找到 ajaxSettings:配置一下即可
-
layui登录后token问题的更多相关文章
- Jmeter通过正则表达式获取登录后token
1.引用名称:即参数化,便于后面调用登录后获取的token 2.正则表达式:"token":"([0-9 a-z -]+?)" 3.模板:设置为 "$ ...
- 利用cookies获取登录后的网页
众所周知,HTTP连接是无状态的,那么问题来了,怎么记录用户的登录信息呢?通常的做法是用户第一次发送HTTP请求时,在HTTP Server端生成一个SessionID,SessionID会对应每个会 ...
- 登录获取token,token参数关联至所有请求的请求体内
问题描述: 有些系统接口判断用户是否登录,是校验登录接口成功后传的token值,也就是请求系统所有接口时,前端传参必带登录成功后接口返回的token,后台以此检验是否过期或是否有登录.所有接口都依赖登 ...
- vue之登录和token处理
应用场景一 Vue刷新token,判断token是否过期.失效,进行登录判断跟token值存储 刷新token和token是否过期的操作都是由后端实现,前端只负责根据code的不同状态来做不同的操作: ...
- OAuth2.0和企业内部统一登录,token验证方式,OAuth2.0的 Authorization code grant 和 Implicit grant区别
统一登录是个很多应用系统都要考虑的问题,多个项目的话最好前期进行统一设计,否则后面改造兼容很麻烦: cas认证的方式:新公司都是老项目,用的是cas认证的方式,比较重而且依赖较多,winform的项目 ...
- 全栈项目|小书架|微信小程序-登录及token鉴权
小程序登录 之前也写过微信小程序登录的相关文章: 微信小程序~新版授权用户登录例子 微信小程序-携带Token无感知登录的网络请求方案 微信小程序开通云开发并利用云函数获取Openid 也可以通过官方 ...
- koa2+mysql+vue实现用户注册、登录、token验证
说明: node.js提供接口,vue展现页面,前后端分离,出于编辑器功能和编辑习惯,vue用HbuilderX,node.js用VScode.(PS:仅作为学习笔记,如有不当之处欢迎指出,在此先谢为 ...
- # RESTful登录(基于token鉴权)的设计实例
使用场景 现在很多基于restful的api接口都有个登录的设计,也就是在发起正式的请求之前先通过一个登录的请求接口,申请一个叫做token的东西.申请成功后,后面其他的支付请求都要带上这个token ...
- iOS登录及token的业务逻辑
登录的业务逻辑 { http:是短连接. 服务器如何判断当前用户是否登录? // 1. 如果是即时通信类:长连接. // 如何保证服务器跟客户端保持长连接状态? // "心跳包" ...
随机推荐
- 【OCP-12c】CUUG 071题库考试原题及答案解析(21)
3.choose three View the Exhibit and examine the description of SALES and PROMOTIONS tables. You want ...
- “全栈2019”Java异常第四章:catch代码块作用域详解
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java异 ...
- php性能优化三(PHP语言本身)
0.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量,单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的“函数”(译注:PHP手册 ...
- 为什么说 Gumroad 是一家 “失败” 的创业公司?
Gumroad 是一家 "失败" 的创业公司. 创立于 2012 年,Gumroad 是一个面向创造者的电商平台.创始人 Sahil Lavingia,一名 19 岁的少年,Pin ...
- leetcode 198 打家劫舍 Python 动态规划
打家劫舍 你是一个专业的小偷,计划偷窃沿街的房屋.每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警. 给定 ...
- JavaScript DOM编程艺术 笔记(四)
DOM document object model(map) 家谱树---节点树 父 子 兄弟 元素节点 <div> 文本节点 内容 属性节点 value src getE ...
- 配置 CentOS 7 安装位置
红框里是CentOS 7安装程序检测到的硬盘,选择你想把系统安装到哪个硬盘当中. 点击 Add disk 按钮可以添加指定的附加设备或者网络设备(通过ISCSI.FCoE等方式添加硬盘) 此处设置分区 ...
- linux常见编辑命令
保存命令 按ESC键 跳到命令模式,然后: :w 保存文件但不退出vi :w file 将修改另外保存到file中,不退出vi :w! 强制保存,不推出vi :wq 保存文件并退出vi :wq! 强制 ...
- TP5 隐藏入口文件 index.php
找到public下的.htaccess <IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine ...
- destoon调用方法汇总 ---转载
根目录.模板目录和样式目录:{DT_PATH}{DT_SKIN}导入头脚:{template 'header'}{template 'footer'}对应模块首页:{$MODULE[$moduleid ...