zoukankan      html  css  js  c++  java
  • 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: /xml/, html: /html/, json: /json/}, 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:配置一下即可

              -

    遇事犹豫不决时,须持虎狼之心,行仁义之事
  • 相关阅读:
    MyEclipse10 复制之前的项目部署到tomcat时项目名称对不上,还是复制前的项目名称,哪里修改设置
    11 The superlative
    jQuery Mobile学习笔记
    MySQL基础
    ANGULAR $HTTP请求
    Effective前端5:减少前端代码耦合
    AJAX的简介
    原生ajax
    Ionic实战 自动升级APP(Android版)
    读取数据库信息构建视图字段的备注信息,方便程序代码生成
  • 原文地址:https://www.cnblogs.com/fmlyzp/p/10663287.html
Copyright © 2011-2022 走看看