vue+ssm+前后分离+jwt认证+ sessionId变动问题 或者cookie丢失问题

环境:vue/cli 4.3 +elementUI+ssm框架+node.js(代理proxyTable 方式的代理,在开发环境下)

我遇到sessionId 总是变化的问题(坑了我好久,故做引路人.....)

1.因为用到的是node.js开发的环境下的代理.所以不存在跨域问题(再说一遍不存在跨域问题).前端代理配置vue.config.js 如下图:

module.exports = {
    css: {
        sourceMap: true,  //设置浏览器调试模式下显示css文件显示路径,方便开发人员调试.
    },
    devServer: {
        port:8080,
        host:'127.0.0.1',
        https:false,
        proxy: {
            '/api': {
                target: 'http://localhost:8088/api',
                changeOrigin: true,
                ws: false,
                pathRewrite: { '^/api': '/' }
            }
        }
    },

};

 

如果你也用上面的代理,那么后台代码不用动..因为代理不会涉及跨域问题,代理顾名思义,你可以想象成前端模拟后台接口访问后台,所以不涉及跨域,项目开发完是放到ngnix 上的.如果不是采用代理方式.请参考其他跨域配置(网上一搜一大堆)

注意要说明的是8080后的api是后端项目名称.必须和 '/api'代理名称一致,否则会导致sessionId 一致变换 .我不清楚为什么,知道的朋友请留言.. 

2.axios 中不需要改变 ..  至于网上说 withCredentials: true 可传cookie 信息,, 仅限于跨域.我们这里采用的是代理,[vue开发环境下的node.js 安装提供的代理],  true或false 无所谓..不会对sessionid有影响.或者说.cookie都能被后端接收..

3.下面代码是生成jwt 生成 token , 拦截token认证即返回值等等一系列代码如下:

前端axios 封装如下 require.js

import axios from 'axios';
import {MessageBox, Message} from 'element-ui';
import store from '../js/store/store';
import {getToken} from '@/utils/auth';
import qs from 'qs';
// axios 封装
const service = axios.create({
    withCredentials: true,// 指定某个请求应该发送凭据。允许客户端携带跨域cookie,也需要此配置
    timeout: 20000, // request timeout
});
service.interceptors.request.use(config => {
        //1.只拦截以*.do 结尾的url ,其他不拦截.  ;
        if (!config.url.endsWith(".do")) {
            return config;
        }
        if (config.method === 'post') { // post请求时,处理数据
            config.data = qs.stringify({
                ...config.data //后台数据接收这块需要以表单形式提交数据,而axios中post默认的提交是json数据,所以这里选用qs模块来处理数据.
            });
        }
        //3.将token 放入axios header 里面,进入后台进行处理判断
        if (store.getters.token) {
            let token = getToken();
            config.headers['X-Token'] = token;
        }
        return config;
    }, error => {
        // axios出现请求异常
        return Promise.reject(error);
    }
);
// axios响应拦截器[这里对后台相应的非200状态拦截,并显示详细信息]
service.interceptors.response.use(response => {
    const res = response.data;
    if (response.status === 200) {  //成功
        //对自定义resultVO状态码做判断[即非运行异常]
        if (res['code'] === undefined) {
            return res;
        }
        if (res != null && res['code'] === 200) { //自定义状态码
            return res;
        } else if (res['code'] === 100000) {
            MessageBox.confirm('您必须重新登录, 或者点击取消保持当前页', '确认退出', {
                confirmButtonText: '重新登录',
                cancelButtonText: '取消',
                type: 'warning'
            }).then(() => {
                store.dispatch('userModule/actionResetToken').then(() => {
                    location.reload();
                });
            });
            return Promise.reject(new Error(res.message || 'Error'));
        } else {
            Message({
                message: res.message || 'Error',
                type: 'error',
                duration: 5 * 1000
            });
            return Promise.reject(new Error(res.message || 'Error'));
        }
    } else {
        Message({
            message: res.message || 'Error',
            type: 'error',
            duration: 5 * 1000
        });
        return Promise.reject(new Error(res.message || 'Error'));
    }
});

export default service;

后端获取token

public class TokenManager {

    public static Logger logger = Logger.getLogger(TokenManager.class);

    /**
     * 获取token
     * by lw on 2020年5月9日 21:45:22
     */
    public static String getToken(User user, HttpServletRequest request) {
        String sessionId = request.getSession().getId();
        long currentTime = System.currentTimeMillis() + 60 * 60 * 1000;//一小时有效时间
        Date end = new Date(currentTime);
        String token = JWT.create().withAudience(user.getId().toString()).withIssuedAt(new Date()).
                withExpiresAt(end).withKeyId(sessionId).sign(Algorithm.HMAC256(user.getPassword()));
        System.out.println("token===================="+token);
        return token;
    }

}

拦截器拦截token

package com.authentication;

import cn.gjing.result.ResultVo;
import com.alibaba.fastjson.JSON;
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.exceptions.JWTVerificationException;
import com.system.auto_generator.SysUser;
import com.system.dao.UserMapper;
import org.apache.log4j.Logger;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;

/**
 * 拦截器,拦截请求中是否带有token ,以及token 的有效性
 */
public class AuthenticationInterceptor implements HandlerInterceptor {

    @Resource
    public UserMapper userMapper;

    private static Logger logger = Logger.getLogger(AuthenticationInterceptor.class);

    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object object) {
        String token = httpServletRequest.getHeader("X-Token");// 从 http 请求头中取出 token
        HttpSession session = httpServletRequest.getSession();
        // step1.如果不是映射到方法直接通过
        if (!(object instanceof HandlerMethod)) {
            return true;
        }
        HandlerMethod handlerMethod = (HandlerMethod) object;
        Method method = handlerMethod.getMethod();
        //检查是否有PassToken注释,有则跳过认证
        if (method.isAnnotationPresent(PassToken.class)) {
            PassToken passToken = method.getAnnotation(PassToken.class);
            if (passToken.required()) {
                return true;
            }
        }
        // step2.获取 token 中的 用户信息
        if (token == null || (! session.getId().equalsIgnoreCase(JWT.decode(token).getKeyId()))) {
            throwException2Axios(httpServletResponse);
            return false;
        }
        String userId;
        try {
            userId = JWT.decode(token).getAudience().get(0);

        } catch (JWTDecodeException j) {
            throwException2Axios(httpServletResponse);
            return false;
        }
        int id = Integer.parseInt(userId);
        SysUser user = userMapper.selectByPrimaryKey(id);
        if (user == null) {
            throwException2Axios(httpServletResponse);
            return false;
        }
        // step3. 验证 token 有消息
        JWTVerifier jwtVerifier = JWT.require(Algorithm.HMAC256(user.getPassword())).build();
        try {
            jwtVerifier.verify(token);
        } catch (JWTVerificationException e) {
            throwException2Axios(httpServletResponse);
            return false;
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest httpServletRequest,
                           HttpServletResponse httpServletResponse,
                           Object o, ModelAndView modelAndView) {
    }

    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest,
                                HttpServletResponse httpServletResponse,
                                Object o, Exception e) {
    }

    /**
     * 返回给axios异常.提示重新登录
     */
    private void throwException2Axios(HttpServletResponse response){
        PrintWriter writer = null;
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            writer = response.getWriter();
            writer.write(JSON.toJSONString(ResultVo.error(100000,"无效的令牌")));
        } catch (IOException e){
            logger.error(e.getMessage(),e);
        } finally {
            if(writer != null){
                writer.close();
            }
        }
    }

}
package com.authentication;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface PassToken {
    boolean required() default true;
}

登陆验证

@PostMapping(value = "/doLogin")
    public ResultVo login(SysUser sysUser, HttpServletRequest request) {
        try {
            if (ParamUtil.isEmpty(sysUser)||ParamUtil.isEmpty(sysUser.getUserName()) || ParamUtil.isEmpty(sysUser.getPassword())) {
                return ResultVo.error("提交信息错误,数据缺失");
            }
            List list = userService.getUserInfoList(sysUser.getUserName());
            if (list.size() == 0) {
                return ResultVo.error("用户名:" + sysUser.getUserName() + "不存在");
            }
            if (list.size() > 1) {
                return ResultVo.error("数据库存在相同用户名:" + sysUser.getUserName());
            }
            User user = list.get(0);
            if (user.getPassword().equalsIgnoreCase(EncryptionUtil.md5(sysUser.getPassword()))) {
                String token = TokenManager.getToken(user, request);
                return ResultVo.success("登陆成功", token);
            } else {
                return ResultVo.error("你的密码错误,请重试。");
            }
        } catch (CannotGetJdbcConnectionException e) {
            e.printStackTrace();
            return ResultVo.error("数据库连接异常:" + e.getMessage());
        } catch (MyBatisSystemException e) {
            e.printStackTrace();
            return ResultVo.error("数据库连接异常:" + e.getMessage());
        } catch (Exception e) {
            e.printStackTrace();
            return ResultVo.error("异常详情:" + e.getMessage());
        }

最后是上的类的拦截器注册



    
    
        
    

    
    
        
            
            
                
            
        
    
    


    
    
        
         
        
        
    
    
    
        
            
             
             
            
        
    

 

你可能感兴趣的:(vue+ssm+前后分离+jwt认证+ sessionId变动问题 或者cookie丢失问题)