JWT前后端分离demo

Posted swqblog

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JWT前后端分离demo相关的知识,希望对你有一定的参考价值。

后端项目完整代码:https://github.com/shenweiquan/jwt-demo

一:准备工作

  1-1 运行环境:

  后端:jdk1.8,springboot,jwt

  前端:vue , elementui

  1-2 创建前端和后端项目

  后端项目结构:

   技术图片

 

 

二:重要的代码

  JwtUtil

package com.swq.jwt.util;

import com.alibaba.fastjson.JSONObject;
import com.swq.jwt.dto.CheckResult;
import com.swq.jwt.entry.User;
import io.jsonwebtoken.*;
import org.apache.tomcat.util.codec.binary.Base64;

import com.swq.jwt.constant.Constant;

import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.Date;

public class JwtUtil {

    /**
     * 由字符串生成key
     *
     * @return
     */
    public static SecretKey generalKey() {
        String Strkey = Constant.JWT_SECRET;//自定义的字符串

        byte[] decode = Base64.decodeBase64(Strkey.getBytes());//解密

        //利用AES加密算法构造密匙
        SecretKey key = new SecretKeySpec(decode, 0, decode.length, "AES");

        return key;
    }

    /**
     * @param id      JWT的唯一标识
     * @param subject
     * @param ttl     过期时间长度
     * @return
     */
    public static String createJWT(
            String id,
            String subject,
            long ttl
    ) {

        long timeMillis = System.currentTimeMillis();//创建jwt时间
        Date date = new Date(timeMillis); //转换为日期

        JwtBuilder jwt = Jwts.builder()
                .setId(id)  //jwt_id
                .setIssuedAt(date) //创建时间
                .setSubject(subject) //sub(Subject):代表这个JWT的主体,即它的所有人,这个是一个json格式的字符串
                .signWith(SignatureAlgorithm.HS256, generalKey());

        //设置过期时间
        if (ttl > 0) {
            long exp = timeMillis + ttl; //过期时间
            Date expDate = new Date(exp);
            jwt.setExpiration(expDate);//设置过期时间

        }

        return jwt.compact();
    }

    /**
     * 解密jwt
     * @param jwt
     * @return
     */
    public  static Claims parseJwt(String jwt)
    {
        SecretKey secretKey = generalKey();

        Claims body = Jwts.parser()
                .setSigningKey(secretKey)
                .parseClaimsJws(jwt).getBody();

        return body;

    }

    /**
     * 获得subject,转化为json字符串
     * @param user
     * @return
     */
    public static String generalSubject(User user)
    {
       return  JSONObject.toJSONString(user);
    }

    /**
     * 验证jwt
     */
    public static CheckResult vaildateJwt(String jtw)
    {
        CheckResult res = new CheckResult();

        Claims claims = null;

        try{
            claims = parseJwt(jtw);
            res.setSuccess(true);
            res.setClaims(claims);
        }
        catch (ExpiredJwtException e1) //过期异常
        {
            res.setSuccess(false);
            res.setErrcode(Constant.JWT_ERRCODE_EXPIRE);
        }
        catch (SignatureException e2) //签名异常
        {
            res.setSuccess(false);
            res.setErrcode(Constant.JWT_ERRCODE_FAIL);
        }
        catch (Exception e)
        {
            res.setSuccess(false);
            res.setErrcode(Constant.JWT_ERRCODE_FAIL);
        }



        return res;
    }
}

  拦截器:

package com.swq.jwt.config;

import com.swq.jwt.Interceptor.interceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;

/**
 * AJAX请求跨域
 * @author Mr.W
 * @time 2018-08-13
 */


@Configuration
public class CorsConfig extends WebMvcConfigurerAdapter {
    static final String ORIGINS[] = new String[] { "GET", "POST", "PUT", "DELETE" };
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**").allowedOrigins("*").allowCredentials(true).allowedMethods(ORIGINS)
                .maxAge(3600);
    }

    //拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
      registry.addInterceptor(new interceptor())
              .addPathPatterns("/**")//需要拦截的url
              .excludePathPatterns("/user/login");//不需要拦截的url

    }
}

 

package com.swq.jwt.Interceptor;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.swq.jwt.dto.CheckResult;
import com.swq.jwt.exception.TokenException;
import com.swq.jwt.util.JwtUtil;
import io.jsonwebtoken.Claims;
import org.apache.tomcat.jni.User;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;


@Component
public class interceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {




        String token = request.getHeader("Authorization");

        if(token == null || token.equals(""))
        {
                throw  new TokenException("token is null");
        }

        CheckResult checkResult = JwtUtil.vaildateJwt(token);

        if(checkResult.isSuccess()) //验证成功
        {
            Claims claims = checkResult.getClaims();
            String subject = claims.getSubject();
            JSONObject parse = JSONObject.parseObject(subject);
            User user = JSON.toJavaObject(parse, User.class);

            return true;
        }
        else
        {
            throw  new TokenException("token parse fail");
        }


    }
}
Constant:
package com.swq.jwt.constant;

/**
 * 常量类
 */
public class Constant {




    //异常
    public static final String JWT_ERRCODE_EXPIRE="token is expire";
    public static final String JWT_ERRCODE_FAIL="unkonw error";


    //jwt需要用到的常量
    public static final String JWT_ID = "SWQ-1998"; //jwt签发者
    //密匙
    public static final String JWT_SECRET = "nfjenfaEINFUNSEFUNBFninwdw";//随便写个,注意长度必须大于16
    //过期时间
    public static final int JWT_TTL = 60 *60 *1000;

}

前端封装axios

//引入安装的axios插件
import axios from ‘axios‘

/****** 创建axios实例 ******/
const service = axios.create({
  //baseURL: process.env.BASE_URL,  // api的base_url
  timeout: 5000  // 请求超时时间
});

service.interceptors.request.use(
  config => {
    if (sessionStorage.getItem(‘token‘)) {  // 判断是否存在token,如果存在的话,则每个http header都加上token
      config.headers.Authorization = sessionStorage.getItem(‘token‘);
    }
    return config;
  },
  err => {
    return Promise.reject(err);
  });

 export default service

登录成功后,后台返回token,前端保存

<template>
  <div style="width:20%;margin:0 auto">



<el-card class="box-card">
  <div slot="header" class="clearfix">
    <span>登录</span>
  </div>
  <div class="text item">
   <el-input v-model="name" placeholder="请输入昵称"></el-input>
        <p></p><p></p>
        <el-input placeholder="请输入密码" v-model="password" show-password></el-input>
  </div>
  <p></p><p></p>
  <el-button @click="login">登录</el-button>
</el-card>


  </div>
</template>

<script>
import service from ‘@/request/http‘

export default {
  data: function() {
    return {
      name:‘‘,
      password: ‘‘
    }
  },

  methods:{
    login(){

        service({
          method:‘post‘,
          url:‘/user/login‘,
          data:{
            name:this.name,
            password:this.password
          }
        })
        .then(res =>{

          if(res.data.success == true)
          {
              sessionStorage.setItem(‘token‘,res.data.data) //保存token
              //跳转到首页
              this.$router.push(‘/index‘)//进入主页
          }
          else
          {

              this.$message.success(res.data.msg);
          }

        })
    }
  }
}
</script>

 

以上是关于JWT前后端分离demo的主要内容,如果未能解决你的问题,请参考以下文章

spring boot2整合shiro安全框架实现前后端分离的JWT token登录验证

SpringSecurity+JWT实现前后端分离的使用#yyds干货盘点#

前后端分离,VueJS为何这么受宠?

Django 前后端分离 JWT 登录

从零玩转SpringSecurity+JWT整合前后端分离-从零玩转springsecurityjwt整合前后端分离

Shrio使用Jwt达到前后端分离