parent
90260bdc41
commit
fd64c134b0
@ -0,0 +1,45 @@
|
||||
package cc.yunxi.common.domain;
|
||||
|
||||
import cn.hutool.core.collection.CollectionUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.metadata.OrderItem;
|
||||
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import javax.validation.constraints.Min;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
||||
@Data
|
||||
@ApiModel(description = "分页查询条件")
|
||||
@Accessors(chain = true)
|
||||
public class PageQueryPlus {
|
||||
public static final Integer DEFAULT_PAGE_SIZE = 20;
|
||||
public static final Integer DEFAULT_PAGE_NUM = 1;
|
||||
@ApiModelProperty("页码")
|
||||
@Min(value = 1, message = "页码不能小于1")
|
||||
private Integer pageNo = DEFAULT_PAGE_NUM;
|
||||
|
||||
@ApiModelProperty("每页个数")
|
||||
@Min(value = 1, message = "每页查询数量不能小于1")
|
||||
private Integer pageSize = DEFAULT_PAGE_SIZE;
|
||||
|
||||
@ApiModelProperty("排序规则")
|
||||
private Collection<SortingFieldDTO> sortingFields;
|
||||
|
||||
// public <T> Page<T> buildPage() {
|
||||
// Page<T> page = new Page<>(pageNo, pageSize);
|
||||
// if (!CollectionUtil.isEmpty(sortingFields)) {
|
||||
// page.addOrder(sortingFields.stream().map(sortingField -> SortingFieldDTO.ORDER_ASC.equals(sortingField.getOrder()) ?
|
||||
// OrderItem.asc(sortingField.getField()) : OrderItem.desc(sortingField.getField()))
|
||||
// .collect(Collectors.toList()));
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
package cc.yunxi.common.domain;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class SortingFieldDTO implements Serializable {
|
||||
|
||||
/**
|
||||
* 顺序 - 升序
|
||||
*/
|
||||
public static final String ORDER_ASC = "asc";
|
||||
/**
|
||||
* 顺序 - 降序
|
||||
*/
|
||||
public static final String ORDER_DESC = "desc";
|
||||
|
||||
/**
|
||||
* 字段
|
||||
*/
|
||||
@ApiModelProperty("字段")
|
||||
private String field;
|
||||
/**
|
||||
* 顺序
|
||||
*/
|
||||
@ApiModelProperty("是否升序")
|
||||
private String order;
|
||||
}
|
@ -0,0 +1,13 @@
|
||||
package cc.yunxi.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "nxhs.auth")
|
||||
public class AuthProperties {
|
||||
private List<String> includePaths;
|
||||
private List<String> excludePaths;
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cc.yunxi.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
import java.time.Duration;
|
||||
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "nxhs.jwt")
|
||||
public class JwtProperties {
|
||||
private Resource location;
|
||||
private String password;
|
||||
private String alias;
|
||||
private Duration tokenTTL = Duration.ofMinutes(10);
|
||||
}
|
@ -0,0 +1,33 @@
|
||||
package cc.yunxi.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.rsa.crypto.KeyStoreKeyFactory;
|
||||
|
||||
import java.security.KeyPair;
|
||||
|
||||
@Configuration
|
||||
@EnableConfigurationProperties(JwtProperties.class)
|
||||
public class SecurityConfig {
|
||||
|
||||
@Bean
|
||||
public PasswordEncoder passwordEncoder(){
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public KeyPair keyPair(JwtProperties properties){
|
||||
// 获取秘钥工厂
|
||||
KeyStoreKeyFactory keyStoreKeyFactory =
|
||||
new KeyStoreKeyFactory(
|
||||
properties.getLocation(),
|
||||
properties.getPassword().toCharArray());
|
||||
//读取钥匙对
|
||||
return keyStoreKeyFactory.getKeyPair(
|
||||
properties.getAlias(),
|
||||
properties.getPassword().toCharArray());
|
||||
}
|
||||
}
|
@ -0,0 +1,76 @@
|
||||
package cc.yunxi.config;
|
||||
|
||||
import cc.yunxi.interceptor.LoginInterceptor;
|
||||
import cc.yunxi.interceptor.StatsInterceptor;
|
||||
import cn.hutool.core.collection.CollUtil;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
|
||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Configuration
|
||||
@RequiredArgsConstructor
|
||||
@EnableConfigurationProperties(AuthProperties.class)
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
private final LoginInterceptor loginInterceptor;
|
||||
private final StatsInterceptor statsInterceptor;
|
||||
private final AuthProperties authProperties;
|
||||
|
||||
// 全局忽略路径
|
||||
private static List<String> globalExcludePaths = Arrays.asList(
|
||||
"/error",
|
||||
"/favicon.ico",
|
||||
"/v2/**",
|
||||
"/v3/**",
|
||||
"/swagger-resources/**",
|
||||
"/webjars/**",
|
||||
"/doc.html"
|
||||
);
|
||||
|
||||
@Override
|
||||
public void addCorsMappings(CorsRegistry registry) {
|
||||
registry.addMapping("/**") // 所有接口
|
||||
.allowCredentials(true) // 是否发送 Cookie
|
||||
.allowedOriginPatterns("*") // 支持域
|
||||
.allowedMethods("GET", "POST", "PUT", "DELETE") // 支持方法
|
||||
.allowedHeaders("*")
|
||||
.exposedHeaders("*");
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void addInterceptors(InterceptorRegistry registry) {
|
||||
// 按顺序执行拦截器
|
||||
this.addStatsInterceptor(registry);
|
||||
this.addLoginInterceptor(registry);
|
||||
}
|
||||
|
||||
// 添加登录拦截器
|
||||
private void addLoginInterceptor(InterceptorRegistry registry) {
|
||||
InterceptorRegistration registration = registry.addInterceptor(loginInterceptor);
|
||||
// 2.配置拦截路径
|
||||
List<String> includePaths = authProperties.getIncludePaths();
|
||||
if (CollUtil.isNotEmpty(includePaths)) {
|
||||
registration.addPathPatterns(includePaths);
|
||||
}
|
||||
// 3.配置放行路径
|
||||
List<String> excludePaths = authProperties.getExcludePaths();
|
||||
if (CollUtil.isNotEmpty(excludePaths)) {
|
||||
registration.excludePathPatterns(excludePaths);
|
||||
}
|
||||
registration.excludePathPatterns(globalExcludePaths);
|
||||
}
|
||||
|
||||
// 添加请求日志拦截器
|
||||
private void addStatsInterceptor(InterceptorRegistry registry) {
|
||||
registry.addInterceptor(statsInterceptor)
|
||||
.addPathPatterns("/**")
|
||||
.excludePathPatterns(globalExcludePaths);
|
||||
}
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package cc.yunxi.config;
|
||||
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 回收员微信配置
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "nxhs.wx.recycler")
|
||||
public class WxHsyProperties {
|
||||
private String appId;
|
||||
private String appSecret;
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package cc.yunxi.controller;
|
||||
|
||||
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 散户信息 前端控制器
|
||||
* </p>
|
||||
*
|
||||
* @author ccongli
|
||||
* @since 2024-02-28 06:08:09
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/client")
|
||||
public class ClientController {
|
||||
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
package cc.yunxi.controller;
|
||||
|
||||
import cc.yunxi.common.domain.PageDTO;
|
||||
import cc.yunxi.common.domain.PageQuery;
|
||||
import cc.yunxi.domain.dto.RecyclerDTO;
|
||||
import cc.yunxi.domain.po.Recycler;
|
||||
import cc.yunxi.service.IRecyclerService;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@Api(tags = "回收员接口")
|
||||
@RestController
|
||||
@RequestMapping("/user")
|
||||
@RequiredArgsConstructor
|
||||
public class RecyclerController {
|
||||
|
||||
private final IRecyclerService recyclerService;
|
||||
|
||||
@ApiOperation("分页查询商品")
|
||||
@GetMapping("/page")
|
||||
public PageDTO<RecyclerDTO> queryItemByPage(PageQuery query) {
|
||||
// 1.分页查询
|
||||
Page<Recycler> result = recyclerService.page(query.toMpPage("good_total", false));
|
||||
// 2.封装并返回
|
||||
return PageDTO.of(result, RecyclerDTO.class);
|
||||
}
|
||||
}
|
@ -0,0 +1,21 @@
|
||||
package cc.yunxi.domain.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 用户信息 DTO
|
||||
*/
|
||||
@Data
|
||||
public class UserDTO {
|
||||
|
||||
private Integer userType; // 1 回收员 2 散户
|
||||
|
||||
private String id;
|
||||
|
||||
private String username;
|
||||
|
||||
private String phone;
|
||||
|
||||
private String token; // 访问token
|
||||
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
package cc.yunxi.domain.dto.form;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class WxLoginDTO {
|
||||
private String code;
|
||||
private String encryptedData;
|
||||
private String iv;
|
||||
private Integer userType; // 1 回收员 2 散户
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
package cc.yunxi.domain.query;
|
||||
|
||||
import cc.yunxi.common.domain.PageQuery;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@Data
|
||||
@ApiModel(description = "回收员查询条件")
|
||||
public class RecyclerQuery extends PageQuery {
|
||||
|
||||
@ApiModelProperty("所属回收站")
|
||||
private String stationId;
|
||||
|
||||
@ApiModelProperty("联系电话")
|
||||
private String mobilePhone;
|
||||
|
||||
@ApiModelProperty("回收员姓名")
|
||||
private String staffsName;
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package cc.yunxi.interceptor;
|
||||
|
||||
import cc.yunxi.domain.dto.UserDTO;
|
||||
import cc.yunxi.utils.JwtTool;
|
||||
import cc.yunxi.utils.UserContext;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
@Component
|
||||
public class LoginInterceptor implements HandlerInterceptor {
|
||||
|
||||
private final JwtTool jwtTool;
|
||||
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
// 1.获取请求头中的 token
|
||||
String token = request.getHeader("authorization");
|
||||
// 2.校验token
|
||||
UserDTO userInfo = jwtTool.parseToken(token);
|
||||
log.info("当前用户信息: 【{}】", userInfo);
|
||||
// 3.存入上下文
|
||||
UserContext.setUser(userInfo);
|
||||
// 4.放行
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
// 清理用户
|
||||
UserContext.removeUser();
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package cc.yunxi.interceptor;
|
||||
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Slf4j
|
||||
public class StatsInterceptor implements HandlerInterceptor {
|
||||
|
||||
public static final String METHOD_REQUEST_ELAPSED_TIME = "method_request_elapsed_time";
|
||||
@Override
|
||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||
request.setAttribute(METHOD_REQUEST_ELAPSED_TIME, System.currentTimeMillis());
|
||||
String requestURI = request.getRequestURI();
|
||||
String method = request.getMethod();
|
||||
String contentType = request.getContentType();
|
||||
log.info("请求路径:【{}】, 请求方法:【{}】, 协议:【{}】", requestURI, method, contentType);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
|
||||
long startMillis = (long) request.getAttribute(METHOD_REQUEST_ELAPSED_TIME);
|
||||
long endMillis = System.currentTimeMillis();
|
||||
log.info("请求耗时:【{}】ms", endMillis - startMillis);
|
||||
}
|
||||
}
|
@ -0,0 +1,18 @@
|
||||
package cc.yunxi.mapper;
|
||||
|
||||
import cc.yunxi.domain.po.Client;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 散户信息 Mapper 接口
|
||||
* </p>
|
||||
*
|
||||
* @author ccongli
|
||||
* @since 2024-02-28 06:08:09
|
||||
*/
|
||||
@Mapper
|
||||
public interface ClientMapper extends BaseMapper<Client> {
|
||||
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
package cc.yunxi.mapper;
|
||||
|
||||
import cc.yunxi.domain.po.Recycler;
|
||||
import cc.yunxi.domain.po.Test;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 回收员表 mapper接口
|
||||
*/
|
||||
@Mapper
|
||||
public interface RecyclerMapper extends BaseMapper<Recycler> {
|
||||
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
package cc.yunxi.service;
|
||||
|
||||
import cc.yunxi.domain.po.Client;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 散户信息 服务类
|
||||
* </p>
|
||||
*
|
||||
* @author ccongli
|
||||
* @since 2024-02-28 06:08:09
|
||||
*/
|
||||
public interface ClientService extends IService<Client> {
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package cc.yunxi.service;
|
||||
|
||||
import cc.yunxi.domain.po.Recycler;
|
||||
import cc.yunxi.domain.po.Test;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
|
||||
/**
|
||||
* 测试表 业务接口
|
||||
*/
|
||||
public interface IRecyclerService extends IService<Recycler> {
|
||||
|
||||
/**
|
||||
* 根据openid获取回收员信息
|
||||
* @param openid
|
||||
* @return Recycler
|
||||
*/
|
||||
Recycler getRecyclerByOpenid(String openid);
|
||||
|
||||
/**
|
||||
* 手机号注册回收员
|
||||
*/
|
||||
Recycler registerRecycler(String phoneNumber, String openId);
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
package cc.yunxi.service.impl;
|
||||
|
||||
import cc.yunxi.domain.po.Client;
|
||||
import cc.yunxi.mapper.ClientMapper;
|
||||
import cc.yunxi.service.ClientService;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* <p>
|
||||
* 散户信息 服务实现类
|
||||
* </p>
|
||||
*
|
||||
* @author ccongli
|
||||
* @since 2024-02-28 06:08:09
|
||||
*/
|
||||
@Service
|
||||
public class ClientServiceImpl extends ServiceImpl<ClientMapper, Client> implements ClientService {
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
package cc.yunxi.service.impl;
|
||||
|
||||
import cc.yunxi.common.exception.BizIllegalException;
|
||||
import cc.yunxi.domain.po.Recycler;
|
||||
import cc.yunxi.mapper.RecyclerMapper;
|
||||
import cc.yunxi.service.IRecyclerService;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 测试表 服务实现类
|
||||
*/
|
||||
@Service
|
||||
public class RecyclerServiceImpl extends ServiceImpl<RecyclerMapper, Recycler> implements IRecyclerService {
|
||||
|
||||
@Resource
|
||||
RecyclerMapper recyclerMapper;
|
||||
|
||||
@Override
|
||||
public Recycler getRecyclerByOpenid(String openid) {
|
||||
Recycler recycler = lambdaQuery().eq(Recycler::getOpenid, openid).one();
|
||||
return recycler;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Recycler registerRecycler(String phoneNumber, String openId) {
|
||||
// 判断手机号是否被注册
|
||||
Recycler recycler = lambdaQuery().eq(Recycler::getMobilePhone, phoneNumber).one();
|
||||
if (ObjectUtil.isNotEmpty(recycler)) {
|
||||
throw new BizIllegalException("该微信号已被注册");
|
||||
}
|
||||
recycler = new Recycler();
|
||||
recycler.setMobilePhone(phoneNumber);
|
||||
recycler.setStaffsName(phoneNumber);
|
||||
recycler.setOpenid(openId);
|
||||
recyclerMapper.insert(recycler);
|
||||
return recycler;
|
||||
}
|
||||
}
|
@ -0,0 +1,100 @@
|
||||
package cc.yunxi.utils;
|
||||
|
||||
import cc.yunxi.common.exception.UnauthorizedException;
|
||||
import cc.yunxi.config.JwtProperties;
|
||||
import cc.yunxi.domain.dto.UserDTO;
|
||||
import cn.hutool.core.exceptions.ValidateException;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.hutool.jwt.JWT;
|
||||
import cn.hutool.jwt.JWTValidator;
|
||||
import cn.hutool.jwt.signers.JWTSigner;
|
||||
import cn.hutool.jwt.signers.JWTSignerUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.security.KeyPair;
|
||||
import java.time.Duration;
|
||||
import java.util.Date;
|
||||
|
||||
@Component
|
||||
public class JwtTool {
|
||||
private final JWTSigner jwtSigner;
|
||||
|
||||
@Autowired
|
||||
@Lazy
|
||||
private JwtProperties jwtProperties;
|
||||
|
||||
public JwtTool(KeyPair keyPair) {
|
||||
this.jwtSigner = JWTSignerUtil.createSigner("rs256", keyPair);
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建 access-token
|
||||
*
|
||||
* @param userDTO 用户信息
|
||||
* @return access-token
|
||||
*/
|
||||
public String createToken(UserDTO userDTO) {
|
||||
// 1.生成jws
|
||||
return JWT.create()
|
||||
.setPayload("user", userDTO)
|
||||
.setExpiresAt(new Date(System.currentTimeMillis() + jwtProperties.getTokenTTL().toMillis()))
|
||||
.setSigner(jwtSigner)
|
||||
.sign();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证 token
|
||||
*/
|
||||
public JWT verifyToken(String token) {
|
||||
// 1.校验token是否为空
|
||||
if (token == null) {
|
||||
throw new UnauthorizedException("请先登录");
|
||||
}
|
||||
// 2.校验jwt
|
||||
JWT jwt;
|
||||
try {
|
||||
jwt = JWT.of(token).setSigner(jwtSigner);
|
||||
} catch (Exception e) {
|
||||
throw new UnauthorizedException("无效的token", e);
|
||||
}
|
||||
// 2.校验jwt是否有效
|
||||
if (!jwt.verify()) {
|
||||
// 验证失败
|
||||
throw new UnauthorizedException("无效的token");
|
||||
}
|
||||
// 3.校验是否过期
|
||||
try {
|
||||
JWTValidator.of(jwt).validateDate();
|
||||
} catch (ValidateException e) {
|
||||
throw new UnauthorizedException("token已过期");
|
||||
}
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token
|
||||
*
|
||||
* @param token token
|
||||
* @return 解析刷新token得到的用户信息
|
||||
*/
|
||||
public UserDTO parseToken(String token) {
|
||||
JWT jwt = verifyToken(token);
|
||||
// 2.数据格式校验
|
||||
JSONObject userPayload = (JSONObject) jwt.getPayload("user");
|
||||
if (userPayload == null) {
|
||||
// 数据为空
|
||||
throw new UnauthorizedException("无效的token");
|
||||
}
|
||||
// 3.数据解析
|
||||
try {
|
||||
return JSONUtil.toBean(userPayload, UserDTO.class);
|
||||
} catch (RuntimeException e) {
|
||||
// 数据格式有误
|
||||
throw new UnauthorizedException("无效的token", e);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,21 +1,26 @@
|
||||
package cc.yunxi.common.utils;
|
||||
package cc.yunxi.utils;
|
||||
|
||||
import cc.yunxi.domain.dto.UserDTO;
|
||||
|
||||
/**
|
||||
* 用户信息上下文
|
||||
*/
|
||||
public class UserContext {
|
||||
private static final ThreadLocal<Long> tl = new ThreadLocal<>();
|
||||
private static final ThreadLocal<UserDTO> tl = new ThreadLocal<>();
|
||||
|
||||
/**
|
||||
* 保存当前登录用户信息到ThreadLocal
|
||||
* @param userId 用户id
|
||||
* @param userInfo 用户id
|
||||
*/
|
||||
public static void setUser(Long userId) {
|
||||
tl.set(userId);
|
||||
public static void setUser(UserDTO userInfo) {
|
||||
tl.set(userInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取当前登录用户信息
|
||||
* @return 用户id
|
||||
*/
|
||||
public static Long getUser() {
|
||||
public static UserDTO getUser() {
|
||||
return tl.get();
|
||||
}
|
||||
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cc.yunxi.mapper.ClientMapper">
|
||||
|
||||
</mapper>
|
@ -0,0 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="cc.yunxi.mapper.ClientMapper">
|
||||
|
||||
</mapper>
|
Binary file not shown.
Loading…
Reference in new issue