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干货盘点#