layui登录后token问题解决

 

layui是一个非常简单且实用的后台管理系统搭建框架,里面的插件丰富使用简单,只需要在原有基础上进行修改即可,但是在数据处理方面略显薄弱,内置的jquery在实际过程中略显不足,若是能添加内置的mvc模式框架那就更好了。

先介绍layui在登录这一块的使用:

登录问题主要是在token的存储调用上,先贴出后台的创建token以及拦截器的代码

首先引入jar包

io.jsonwebtokenjjwt0.7.0jackson-databindcom.fasterxml.jackson.core

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 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('
' + (t[n.msgName] || "返回的数据不符合规范,正确的成功状态码 (" + n.statusName + ") 应为:" + n.statusCode) + "
")) : (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('
数据接口请求异常:' + t + "
"), 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:配置一下即可

文章来源于互联网: layui登录后token问题解决

赞(0) 打赏
未经允许不得转载:传奇私服 - 传奇私服发布网,最好玩、最新潮的传奇SF尽在眼前 » layui登录后token问题解决

评论 27

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址