整合JWT令牌
一、不在拦截器使用
1、在模块中添加jwt工具依赖
<dependencies>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
</dependency>
</dependencies>
package com.stu.service.base.utils;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/******************************
* 用途说明:
* 作者姓名: Administrator
* 创建时间: 2022-06-30 21:47
******************************/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class JwtInfo {
private String id;
private String nickName;
private String avatar;
//权限、角色等
//不要存敏感信息
}
JwtUtils
package com.stu.service.base.utils;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.joda.time.DateTime;
import org.springframework.util.StringUtils;
import javax.crypto.spec.SecretKeySpec;
import javax.servlet.http.HttpServletRequest;
import javax.xml.bind.DatatypeConverter;
import java.security.Key;
import java.util.Date;
/******************************
* 用途说明:jwt工具类
* 作者姓名: Administrator
* 创建时间: 2022-06-30 21:48
******************************/
public class JwtUtils {
public static final String APP_SECRET = "sdfGRRD323FGSfdrtr4233";
private static Key getKeyInstance() {
SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
byte[] bytes = DatatypeConverter.parseBase64Binary(APP_SECRET);
return new SecretKeySpec(bytes, signatureAlgorithm.getJcaName());
}
/**
* 获取 jwt token
*
* @param jwtInfo 实体
* @param expire 过期时间 m
* @return 生成的 token
*/
public static String getJwtToken(JwtInfo jwtInfo, int expire) {
String JwtToken = Jwts.builder()
.setHeaderParam("typ", "JWT")
.setHeaderParam("alg", "HS256")
// 主题
.setSubject("stu-user")
// 颁发时间
.setIssuedAt(new Date())
// 过期时间
.setExpiration(DateTime.now().plusSeconds(expire).toDate())
// 用户id
.claim("id", jwtInfo.getId())
// 用户昵称
.claim("nickName", jwtInfo.getNickName())
// 用户头像
.claim("avatar", jwtInfo.getAvatar())
.signWith(SignatureAlgorithm.HS256, getKeyInstance())
.compact();
return JwtToken;
}
/**
* 判断token是否存在与有效
*
* @param jwtToken
* @return
*/
public static boolean checkJwtToken(String jwtToken) {
if (StringUtils.isEmpty(jwtToken)) {
return false;
}
try {
Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
} catch (Exception e) {
e.printStackTrace();
return false;
}
return true;
}
/**
* 判断token是否存在与有效
*
* @param request
* @return
*/
public static boolean checkJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
return checkJwtToken(jwtToken);
}
/**
* 根据token获取会员信息
*
* @param request
* @return
*/
public static JwtInfo getMemberIdByJwtToken(HttpServletRequest request) {
String jwtToken = request.getHeader("token");
if (StringUtils.isEmpty(jwtToken)) {
return null;
}
Jws<Claims> claimsJws = Jwts.parser().setSigningKey(getKeyInstance()).parseClaimsJws(jwtToken);
Claims claims = claimsJws.getBody();
JwtInfo jwtInfo = new JwtInfo(claims.get("id").toString(), claims.get("nickName").toString(), claims.get(
"avatar").toString());
return jwtInfo;
}
}
3、使用
package com.stu.service.trade.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.stu.service.base.dto.CourseDto;
import com.stu.service.base.dto.MemberDto;
import com.stu.service.base.exception.CustomException;
import com.stu.service.base.result.R;
import com.stu.service.base.result.ResultCodeEnum;
import com.stu.service.base.utils.JwtInfo;
import com.stu.service.base.utils.JwtUtils;
import com.stu.service.trade.entity.Order;
import com.stu.service.trade.feign.EduCourseService;
import com.stu.service.trade.feign.UcenctMemberService;
import com.stu.service.trade.mapper.OrderMapper;
import com.stu.service.trade.service.OrderService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.stu.service.trade.utli.OrderUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
/**
* <p>
* 订单 服务实现类
* </p>
*
* @author stu
* @since 2022-07-10
*/
@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {
@Autowired
private EduCourseService eduCourseService;
@Autowired
private UcenctMemberService ucenctMemberService;
/***********************************
* 用途说明:新增订单
* @param courseId
* @param request
* 返回值说明:
* @return java.lang.String
***********************************/
@Override
public String saveOrder(String courseId, HttpServletRequest request) {
Order addOrder = null;
JwtInfo jwtInfo = JwtUtils.getMemberIdByJwtToken(request);
if (null == jwtInfo) {
throw new CustomException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
}
String memberId = jwtInfo.getId();
if (StringUtils.isEmpty(memberId)) {
throw new CustomException(ResultCodeEnum.FETCH_ACCESSTOKEN_FAILD);
}
//查询当前用户是否已有当前课程的订单
QueryWrapper<Order> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("course_id", courseId);
queryWrapper.eq("member_id", memberId);
Order order = baseMapper.selectOne(queryWrapper);
if (null != order) {
return order.getId();
}
//查询用户信息
MemberDto memberDto = ucenctMemberService.getMemberInfo(memberId);
if (null == memberDto) {
throw new CustomException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
}
//查询课程信息
CourseDto courseDto = eduCourseService.getCourseById(courseId);
if (null == courseDto) {
throw new CustomException(ResultCodeEnum.ILLEGAL_CALLBACK_REQUEST_ERROR);
}
addOrder = new Order();
addOrder.setOrderNo(OrderUtils.getOrderNo());
addOrder.setCourseId(courseId);
addOrder.setCourseId(courseDto.getId());
addOrder.setCourseTitle(courseDto.getTitle());
addOrder.setCourseCover(courseDto.getCover());
addOrder.setTotalFee(courseDto.getPrice());
addOrder.setTeacherName(courseDto.getTeacherName());
addOrder.setMemberId(memberId);
addOrder.setNickname(jwtInfo.getNickName());
addOrder.setMobile(memberDto.getMobile());
addOrder.setStatus(0);//"订单状态(0:未支付 1:已支付)"
addOrder.setPayType(1);
baseMapper.insert(addOrder);
return addOrder.getId();
}
/***********************************
* 用途说明:支付成功
* @param orderId
* 返回值说明:
* @return boolean
***********************************/
@Override
public Order updateOrderStraus(String orderId) {
Order order = baseMapper.selectById(orderId);
order.setStatus(1);
eduCourseService.updateBuyCountById(order.getCourseId());
return order;
}
}
4、vue页面
import axios from 'axios'
import { Message, MessageBox } from 'element-ui'
import store from '../store'
import { getToken } from '@/utils/auth'
// 创建axios实例
const service = axios.create({
baseURL: process.env.BASE_API, // api的base_url
timeout: 5000 // 请求超时时间
})
// request拦截器
service.interceptors.request.use(
config => {
if (store.getters.token) {
config.headers['token'] = getToken() // 让每个请求携带自定义token 请根据实际情况自行修改
}
return config
},
error => {
// Do something with request error
console.log(error) // for debug
Promise.reject(error)
}
)
// respone拦截器
service.interceptors.response.use(
response => {
/**
* code为非20000是抛错 可结合自己业务进行修改
*/
const res = response.data
if (res.code !== 20000) {
Message({
message: res.message,
type: 'error',
duration: 5 * 1000
})
// 50008:非法的token; 50012:其他客户端登录了; 50014:Token 过期了;
if (res.code === 50008 || res.code === 50012 || res.code === 50014) {
MessageBox.confirm(
'你已被登出,可以取消继续留在该页面,或者重新登录',
'确定登出',
{
confirmButtonText: '重新登录',
cancelButtonText: '取消',
type: 'warning'
}
).then(() => {
store.dispatch('FedLogOut').then(() => {
location.reload() // 为了重新实例化vue-router对象 避免bug
})
})
}
return Promise.reject('error')
} else {
return response.data
}
},
error => {
console.log('err' + error) // for debug
Message({
message: error.message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
export default service
二、通过拦截器方式验证
创建拦截器
package com.qfedu.fmmall.interceptor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qfedu.fmmall.vo.ResStatus;
import com.qfedu.fmmall.vo.ResultVO;
import io.jsonwebtoken.*;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Component
public class CheckTokenInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String method = request.getMethod();
if("OPTIONS".equalsIgnoreCase(method)){
return true;
}
String token = request.getHeader("token");
if(token == null){
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
doResponse(response,resultVO);
}else{
try {
JwtParser parser = Jwts.parser();
parser.setSigningKey("QIANfeng6666"); //解析token的SigningKey必须和生成token时设置密码一致
//如果token正确(密码正确,有效期内)则正常执行,否则抛出异常
Jws<Claims> claimsJws = parser.parseClaimsJws(token);
return true;
}catch (ExpiredJwtException e){
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_OVERDUE, "登录过期,请重新登录!", null);
doResponse(response,resultVO);
}catch (UnsupportedJwtException e){
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "Token不合法,请自重!", null);
doResponse(response,resultVO);
}catch (Exception e){
ResultVO resultVO = new ResultVO(ResStatus.LOGIN_FAIL_NOT, "请先登录!", null);
doResponse(response,resultVO);
}
}
return false;
}
private void doResponse(HttpServletResponse response,ResultVO resultVO) throws IOException {
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
PrintWriter out = response.getWriter();
String s = new ObjectMapper().writeValueAsString(resultVO);
out.print(s);
out.flush();
out.close();
}
}
配置拦截器
package com.qfedu.fmmall.config;
import com.qfedu.fmmall.interceptor.CheckTokenInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class InterceptorConfig implements WebMvcConfigurer {
@Autowired
private CheckTokenInterceptor checkTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(checkTokenInterceptor)
.addPathPatterns("/shopcart/**")
.addPathPatterns("/orders/**")
.addPathPatterns("/useraddr/**")
.addPathPatterns("/user/check");
}
}
axios通过请求头传值
axios({
method: "get",
url: baseUrl + "shopcart/list",
headers: {
token: this.token
}
}).then(function(res) {
console.log(res);
});
各种异常
JwtException 总异常
ClaimJwtException 获取Claim异常
ExpiredJwtException token过期异常
IncorrectClaimException token无效
MalformedJwtException 密钥验证不一致
MissingClaimException JWT无效
RequiredTypeException 必要类型异常
SignatureException 签名异常
UnsupportedJwtException 不支持JWT异常
作者:明
出处:https://www.cnblogs.com/konglxblog//
版权:本文版权归作者和博客园共有
转载:欢迎转载,文章中请给出原文连接,此文章仅为个人知识学习分享,否则必究法律责任