站长资讯网
最全最丰富的资讯网站

layui登录后token问题解决

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: /bxmlb/, html: /bhtml/, json: /bjsonb/},             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:配置一下即可

赞(0)
分享到: 更多 (0)
网站地图   沪ICP备18035694号-2    沪公网安备31011702889846号