1、不同模块登录之后,租户ID的处理,2、新增绑定短信接口

This commit is contained in:
starrySky
2024-04-10 17:02:54 +08:00
parent e8b6c8e0aa
commit e4032a0183
33 changed files with 604 additions and 279 deletions

View File

@@ -2,8 +2,8 @@ package com.starry.admin.common.aspect;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.ServiceException;
import com.starry.admin.modules.clear.mapper.PlayClerkUserInfoMapper;
import com.starry.admin.modules.clear.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clear.service.impl.PlayClerkUserInfoServiceImpl;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.common.constant.Constants;
import com.starry.common.constant.HttpStatus;
@@ -28,8 +28,11 @@ import java.util.Objects;
@Component
public class ClerkUserLoginAspect {
@Resource
private PlayClerkUserInfoMapper userMapper;
private PlayClerkUserInfoServiceImpl clerkUserInfoService;
@Resource
private WxTokenService tokenService;
@Resource
@@ -46,12 +49,12 @@ public class ClerkUserLoginAspect {
// 解析token
String userId;
try {
userId = tokenService.getMiniUserIdByToken(userToken);
userId = tokenService.getWxUserIdByToken(userToken);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
}
PlayClerkUserInfoEntity entity = userMapper.selectById(userId);
PlayClerkUserInfoEntity entity = clerkUserInfoService.selectById(userId);
if (Objects.isNull(entity)) {
throw new ServiceException("未查询到有效用户", HttpStatus.UNAUTHORIZED);
}

View File

@@ -2,8 +2,8 @@ package com.starry.admin.common.aspect;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.ServiceException;
import com.starry.admin.modules.custom.mapper.PlayCustomUserInfoMapper;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.custom.service.impl.PlayCustomUserInfoServiceImpl;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.common.constant.Constants;
import com.starry.common.constant.HttpStatus;
@@ -29,7 +29,8 @@ import java.util.Objects;
public class CustomUserLoginAspect {
@Resource
private PlayCustomUserInfoMapper userMapper;
private PlayCustomUserInfoServiceImpl customUserInfoService;
@Resource
private WxTokenService tokenService;
@Resource
@@ -46,12 +47,12 @@ public class CustomUserLoginAspect {
// 解析token
String userId;
try {
userId = tokenService.getMiniUserIdByToken(userToken);
userId = tokenService.getWxUserIdByToken(userToken);
} catch (Exception e) {
log.error(e.getMessage(), e);
throw new ServiceException("获取用户信息异常", HttpStatus.UNAUTHORIZED);
}
PlayCustomUserInfoEntity entity = userMapper.selectById(userId);
PlayCustomUserInfoEntity entity = customUserInfoService.selectById(userId);
if (Objects.isNull(entity)) {
throw new ServiceException("未查询到有效用户", HttpStatus.UNAUTHORIZED);
}

View File

@@ -1,9 +1,14 @@
package com.starry.admin.common.exception;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* @author 业务异常
* @since 2023/3/9
*/
@EqualsAndHashCode(callSuper = true)
@Data
public class ServiceException extends RuntimeException {
private static final long serialVersionUID = 1L;
@@ -38,9 +43,6 @@ public class ServiceException extends RuntimeException {
this.code = code;
}
public String getDetailMessage() {
return detailMessage;
}
public ServiceException setDetailMessage(String detailMessage) {
this.detailMessage = detailMessage;
@@ -56,8 +58,4 @@ public class ServiceException extends RuntimeException {
this.message = message;
return this;
}
public Integer getCode() {
return code;
}
}

View File

@@ -88,4 +88,11 @@ public class GlobalExceptionHandler {
public R customException(CustomException e) {
return R.error(e.getMessage());
}
// @ExceptionHandler(ServiceException.class)
// public R serviceException(ServiceException e) {
// return R.error(e.getMessage());
// }
}

View File

@@ -1,10 +1,15 @@
package com.starry.admin.common.mybatis.handler;
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.constant.Constants;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Date;
/**
@@ -16,29 +21,53 @@ import java.util.Date;
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Resource
private HttpServletRequest request;
@Resource
private WxTokenService tokenService;
@Override
public void insertFill(MetaObject metaObject) {
log.info("start insert fill ....");
this.setFieldValByName("createdTime", new Date(), metaObject);
this.setFieldValByName("deleted", false, metaObject);
this.setFieldValByName("version", 1L, metaObject);
// Object createUser = this.getFieldValByName("createdBy", metaObject);
// if (createUser == null) {
// if (SecurityUtils.isLogin()) {
// this.setFieldValByName("createdBy", SecurityUtils.getUserId(), metaObject);
// }
// }
Object createUser = this.getFieldValByName("createdBy", metaObject);
if (createUser == null) {
if (SecurityUtils.isLogin()) {
this.setFieldValByName("createdBy", getOperatorId(), metaObject);
}
}
}
@Override
public void updateFill(MetaObject metaObject) {
log.info("start update fill ....");
this.setFieldValByName("updatedTime", new Date(), metaObject);
// Object createUser = this.getFieldValByName("updatedBy", metaObject);
// if (createUser == null) {
// if (SecurityUtils.isLogin()) {
// this.setFieldValByName("updatedBy", SecurityUtils.getUserId(), metaObject);
// }
// }
Object createUser = this.getFieldValByName("updatedBy", metaObject);
if (createUser == null) {
this.setFieldValByName("createdBy", getOperatorId(), metaObject);
}
}
public String getOperatorId() {
if (request.getServletPath().startsWith("/wx/")) {
String clerkToken = request.getHeader(Constants.CLERK_USER_LOGIN_TOKEN);
String customToken = request.getHeader(Constants.CUSTOM_USER_LOGIN_TOKEN);
if (clerkToken != null) {
return tokenService.getWxUserIdByToken(clerkToken);
}
if (customToken != null) {
return tokenService.getWxUserIdByToken(customToken);
}
return "";
} else {
if (SecurityUtils.isLogin()) {
return SecurityUtils.getUserId();
}
}
return "";
}
}
}

View File

@@ -1,32 +0,0 @@
package com.starry.admin.common.security;
import javax.servlet.*;
import java.io.IOException;
/**
* @author admin
* @since 2024/4/7 17:17
**/
public class CustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) {
// 初始化代码
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
// 在请求处理之前可以进行一些操作
// 例如,可以记录请求开始时间
System.out.println("--------------------");
// 继续调用下一个Filter或servlet
chain.doFilter(request, response);
// 在请求处理之后可以进行一些操作
// 例如,可以记录请求结束时间并计算耗时
}
@Override
public void destroy() {
// 销毁代码
}
}

View File

@@ -50,25 +50,13 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()// 由于使用的是JWT我们这里不需要csrf
.sessionManagement()// 基于token所以不需要session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()
// 允许对于网站静态资源的无授权访问
.antMatchers(HttpMethod.GET,
"/",
"/*.html",
"/favicon.ico",
"/**/*.html",
"/**/*.css",
"/**/*.js",
"/swagger-resources/**",
"/v2/api-docs/**"
).permitAll()
.antMatchers(HttpMethod.GET, "/", "/*.html", "/favicon.ico", "/**/*.html", "/**/*.css", "/**/*.js", "/swagger-resources/**", "/v2/api-docs/**").permitAll()
// 对登录注册要允许匿名访问
.antMatchers("/login", "/captcha/get-captcha", "/wx/**").permitAll()
// 跨域请求会先进行一次options请求
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest()// 除上面外的所有请求全部需要鉴权认证
.antMatchers(HttpMethod.OPTIONS).permitAll().anyRequest()// 除上面外的所有请求全部需要鉴权认证
.authenticated();
// 禁用缓存
httpSecurity.headers().cacheControl();
@@ -77,15 +65,12 @@ public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
// 添加JWT filter
httpSecurity.addFilterBefore(jwtAuthenticationTokenFilter(), UsernamePasswordAuthenticationFilter.class);
// 添加自定义未授权和未登录结果返回
httpSecurity.exceptionHandling()
.accessDeniedHandler(customAccessDeniedHandler)
.authenticationEntryPoint(customAuthenticationEntryPoint);
httpSecurity.exceptionHandling().accessDeniedHandler(customAccessDeniedHandler).authenticationEntryPoint(customAuthenticationEntryPoint);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService())
.passwordEncoder(passwordEncoder());
auth.userDetailsService(userDetailsService()).passwordEncoder(passwordEncoder());
}
@Bean

View File

@@ -3,8 +3,13 @@ package com.starry.admin.common.security.filter;
import com.starry.admin.common.component.JwtToken;
import com.starry.admin.common.domain.LoginUser;
import com.starry.admin.modules.clear.service.impl.PlayClerkUserInfoServiceImpl;
import com.starry.admin.modules.custom.service.impl.PlayCustomUserInfoServiceImpl;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.constant.Constants;
import com.starry.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
@@ -26,23 +31,48 @@ import java.io.IOException;
@Slf4j
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Resource
WxTokenService tokenService;
@Value("${jwt.tokenHeader}")
private String tokenHeader;
@Value("${jwt.tokenHead}")
private String tokenHead;
@Resource
private JwtToken jwtToken;
@Resource
private PlayCustomUserInfoServiceImpl customUserInfoService;
@Resource
private PlayClerkUserInfoServiceImpl clerkUserInfoService;
@Override
protected void doFilterInternal(@NotNull HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {
LoginUser jwtUser = jwtToken.getNewLoginUser(httpServletRequest);
if (null != jwtUser && null == SecurityContextHolder.getContext().getAuthentication()) {
jwtToken.verifyToken(jwtUser);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
// 微信公众号的请求
if (httpServletRequest.getServletPath().startsWith("/wx/")) {
String clerkToken = httpServletRequest.getHeader(Constants.CLERK_USER_LOGIN_TOKEN);
String customToken = httpServletRequest.getHeader(Constants.CUSTOM_USER_LOGIN_TOKEN);
if (StringUtils.isNotEmpty(clerkToken) || StringUtils.isNotEmpty(customToken)) {
String userId = tokenService.getWxUserIdByToken(StringUtils.isNotEmpty(clerkToken) ? clerkToken : customToken);
if (clerkToken != null) {
SecurityUtils.setTenantId(clerkUserInfoService.selectById(userId).getTenantId());
} else {
SecurityUtils.setTenantId(customUserInfoService.selectById(userId).getTenantId());
}
} else {
// 如果是微信端接口并且未登录的话从head中获取token
String header = httpServletRequest.getHeader("tenantkey");
// 根据租户表信息查询租户ID暂时先写死
String tenantId = "9999";
SecurityUtils.setTenantId(header);
}
} else {
// 管理端的请求
LoginUser jwtUser = jwtToken.getNewLoginUser(httpServletRequest);
if (null != jwtUser && null == SecurityContextHolder.getContext().getAuthentication()) {
jwtToken.verifyToken(jwtUser);
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(jwtUser, null, jwtUser.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(httpServletRequest));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
filterChain.doFilter(httpServletRequest, httpServletResponse);
}

View File

@@ -80,7 +80,7 @@ public class PlayClerkUserInfoController {
@PreAuthorize("@customSs.hasPermission('play:info:query')")
@GetMapping(value = "/{id}")
public R getInfo(@PathVariable("id") String id) {
return R.ok(playClerkUserInfoService.selectPlayClerkUserInfoById(id));
return R.ok(playClerkUserInfoService.selectById(id));
}

View File

@@ -36,7 +36,18 @@ public interface IPlayClerkUserInfoService extends IService<PlayClerkUserInfoEnt
* @param id 店员主键
* @return 店员
*/
PlayClerkUserInfoEntity selectPlayClerkUserInfoById(String id);
PlayClerkUserInfoEntity selectById(String id);
/**
* 跟新token
*
* @param id 用户ID
* @param token token
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/9 14:30
**/
void updateTokenById(String id, String token);
/**
* 查询店员列表

View File

@@ -49,8 +49,18 @@ public class PlayClerkUserInfoServiceImpl extends ServiceImpl<PlayClerkUserInfoM
* @return 店员
*/
@Override
public PlayClerkUserInfoEntity selectPlayClerkUserInfoById(String id) {
public PlayClerkUserInfoEntity selectById(String id) {
return this.baseMapper.selectById(id);
}
@Override
public void updateTokenById(String id, String token) {
PlayClerkUserInfoEntity entity = new PlayClerkUserInfoEntity();
entity.setToken(token);
entity.setId(id);
this.baseMapper.updateById(entity);
}
/**

View File

@@ -48,7 +48,7 @@ public class PlayCustomUserInfoController {
@PreAuthorize("@customSs.hasPermission('play:info:query')")
@GetMapping(value = "/{id}")
public R getInfo(@PathVariable("id") String id) {
return R.ok(playCustomUserInfoService.selectPlayCustomUserInfoById(id));
return R.ok(playCustomUserInfoService.selectById(id));
}
/**

View File

@@ -28,7 +28,7 @@ public interface IPlayCustomUserInfoService extends IService<PlayCustomUserInfoE
* @param id 顾客主键
* @return 顾客
*/
PlayCustomUserInfoEntity selectPlayCustomUserInfoById(String id);
PlayCustomUserInfoEntity selectById(String id);
/**
* 查询顾客列表
@@ -46,6 +46,16 @@ public interface IPlayCustomUserInfoService extends IService<PlayCustomUserInfoE
*/
boolean create(PlayCustomUserInfoEntity playCustomUserInfo);
/**
* 跟新token
*
* @param id UUID
* @param token TOKEN
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/9 14:33
**/
void updateTokenById(String id, String token);
/**
* 修改顾客
*

View File

@@ -40,7 +40,7 @@ public class PlayCustomUserInfoServiceImpl extends ServiceImpl<PlayCustomUserInf
* @return 顾客
*/
@Override
public PlayCustomUserInfoEntity selectPlayCustomUserInfoById(String id) {
public PlayCustomUserInfoEntity selectById(String id) {
return this.baseMapper.selectById(id);
}
@@ -70,6 +70,15 @@ public class PlayCustomUserInfoServiceImpl extends ServiceImpl<PlayCustomUserInf
return save(playCustomUserInfo);
}
@Override
public void updateTokenById(String id, String token) {
PlayCustomUserInfoEntity entity = new PlayCustomUserInfoEntity();
entity.setToken(token);
entity.setId(id);
this.baseMapper.updateById(entity);
}
/**
* 修改顾客
*

View File

@@ -1,25 +1,13 @@
package com.starry.admin.modules.system.controller;
import cn.hutool.core.io.FileUtil;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.starry.admin.modules.system.entity.SysAdministrativeAreaDictInfoEntity;
import com.starry.admin.modules.system.service.ISysAdministrativeAreaDictInfoService;
import com.starry.admin.modules.system.vo.AdministrativeAreaQueryReturnVo;
import com.starry.common.result.R;
import com.starry.common.utils.ConvertUtil;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 行政区域字典信息Controller
@@ -38,39 +26,8 @@ public class AdministrativeAreaDictInfoController {
*/
@PreAuthorize("@customSs.hasPermission('play:info:list')")
@GetMapping("/tree")
public R list() {
List<AdministrativeAreaQueryReturnVo> result = new ArrayList<>();
List<SysAdministrativeAreaDictInfoEntity> list = playAdministrativeAreaDictInfoService.selectAll();
Map<String, List<SysAdministrativeAreaDictInfoEntity>> collect = list.stream().filter(a -> a != null && a.getPCode() != null).collect(Collectors.groupingBy(SysAdministrativeAreaDictInfoEntity::getPCode));
if (collect.containsKey("00")) {
result = ConvertUtil.entityToVoList(collect.get("00"), AdministrativeAreaQueryReturnVo.class);
}
for (AdministrativeAreaQueryReturnVo vo : result) {
vo.setChild(ConvertUtil.entityToVoList(collect.get(vo.getCode()), AdministrativeAreaQueryReturnVo.class));
}
return R.ok(result);
}
@GetMapping("/add")
public R add(@RequestParam("index") String index) {
String fileName = "D:\\" + index + ".txt";
JSONArray array = JSONArray.parse(FileUtil.readString(new File(fileName), "UTF-8"));
List<SysAdministrativeAreaDictInfoEntity> list = new ArrayList<>();
for (int i = 0; i < array.size(); i++) {
JSONObject jsonObject = array.getJSONObject(i);
SysAdministrativeAreaDictInfoEntity entity = new SysAdministrativeAreaDictInfoEntity();
entity.setCode(jsonObject.getString("code"));
entity.setName(jsonObject.getString("name"));
if (index.equals("1")) {
entity.setPCode("00");
} else {
entity.setPCode(jsonObject.getString("provinceCode"));
}
entity.setLevel(index);
list.add(entity);
}
playAdministrativeAreaDictInfoService.saveBatch(list);
return R.ok("");
public R list() throws Exception {
return R.ok(playAdministrativeAreaDictInfoService.selectTree("2"));
}
}

View File

@@ -1,10 +1,13 @@
package com.starry.admin.modules.system.entity;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.starry.common.domain.BaseEntity;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* 行政区域字典信息对象 play_administrative_area_dict_info
*
@@ -43,4 +46,13 @@ public class SysAdministrativeAreaDictInfoEntity extends BaseEntity<SysAdministr
private String level;
/**
* 子数据
*
* @since 2024/4/10 15:09
**/
@TableField(exist = false)
private List<SysAdministrativeAreaDictInfoEntity> child;
}

View File

@@ -3,6 +3,7 @@ package com.starry.admin.modules.system.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import com.starry.admin.modules.system.entity.SysAdministrativeAreaDictInfoEntity;
import com.starry.admin.modules.system.vo.AdministrativeAreaQueryReturnVo;
import java.util.List;
@@ -23,6 +24,16 @@ public interface ISysAdministrativeAreaDictInfoService extends IService<SysAdmin
SysAdministrativeAreaDictInfoEntity selectPlayAdministrativeAreaDictInfoById(String id);
/**
* 查询树形接口的区域信息
*
* @param level 行政区域等级1省级别,2:城市级别:4:区县级别)
* @return List<AdministrativeAreaQueryReturnVo>
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 14:47
**/
List<AdministrativeAreaQueryReturnVo> selectTree(String level);
/**
* 查询所有行政区域字典信息列表
*
@@ -45,6 +56,7 @@ public interface ISysAdministrativeAreaDictInfoService extends IService<SysAdmin
* @return 结果
*/
boolean create(SysAdministrativeAreaDictInfoEntity playAdministrativeAreaDictInfo);
boolean create(List<SysAdministrativeAreaDictInfoEntity> list);
/**

View File

@@ -6,14 +6,19 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.starry.admin.modules.system.mapper.SysAdministrativeAreaDictInfoMapper;
import com.starry.admin.modules.system.entity.SysAdministrativeAreaDictInfoEntity;
import com.starry.admin.modules.system.mapper.SysAdministrativeAreaDictInfoMapper;
import com.starry.admin.modules.system.service.ISysAdministrativeAreaDictInfoService;
import com.starry.admin.modules.system.vo.AdministrativeAreaQueryReturnVo;
import com.starry.common.utils.ConvertUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 行政区域字典信息Service业务层处理
@@ -37,12 +42,39 @@ public class SysAdministrativeAreaDictInfoServiceImpl extends ServiceImpl<SysAdm
return this.baseMapper.selectById(id);
}
@Override
public List<AdministrativeAreaQueryReturnVo> selectTree(String level) {
List<AdministrativeAreaQueryReturnVo> result = new ArrayList<>();
LambdaQueryWrapper<SysAdministrativeAreaDictInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<>();
lambdaQueryWrapper.le(SysAdministrativeAreaDictInfoEntity::getLevel, level);
List<SysAdministrativeAreaDictInfoEntity> list = this.baseMapper.selectList(lambdaQueryWrapper);
Map<String, List<SysAdministrativeAreaDictInfoEntity>> collect = list.stream().filter(a -> a != null && a.getPCode() != null).collect(Collectors.groupingBy(SysAdministrativeAreaDictInfoEntity::getPCode));
return this.assembleTree(collect, collect.get("00"));
}
/**
* 组装数据
*
* @param data 数据key=区域编码,value=区域列表
* @param list 区域略表
* @return List<com.starry.admin.modules.system.entity.SysAdministrativeAreaDictInfoEntity>
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 15:14
**/
public List<AdministrativeAreaQueryReturnVo> assembleTree(Map<String, List<SysAdministrativeAreaDictInfoEntity>> data, List<SysAdministrativeAreaDictInfoEntity> list) {
if (list == null) {
return new ArrayList<>();
}
List<AdministrativeAreaQueryReturnVo> result = ConvertUtil.entityToVoList(list, AdministrativeAreaQueryReturnVo.class);
for (AdministrativeAreaQueryReturnVo entity : result) {
entity.setChild(assembleTree(data, data.get(entity.getCode())));
}
return result;
}
@Override
public List<SysAdministrativeAreaDictInfoEntity> selectAll() {
LambdaQueryWrapper<SysAdministrativeAreaDictInfoEntity> lambdaQueryWrapper = new LambdaQueryWrapper<SysAdministrativeAreaDictInfoEntity>();
lambdaQueryWrapper.eq(SysAdministrativeAreaDictInfoEntity::getLevel, "1").or().eq(SysAdministrativeAreaDictInfoEntity::getLevel, "2");
return this.baseMapper.selectList(lambdaQueryWrapper);
return this.baseMapper.selectList(new LambdaQueryWrapper<>());
}
/**
@@ -54,7 +86,7 @@ public class SysAdministrativeAreaDictInfoServiceImpl extends ServiceImpl<SysAdm
@Override
public IPage<SysAdministrativeAreaDictInfoEntity> selectPlayAdministrativeAreaDictInfoByPage(SysAdministrativeAreaDictInfoEntity playAdministrativeAreaDictInfo) {
Page<SysAdministrativeAreaDictInfoEntity> page = new Page<>(1, 10);
return this.baseMapper.selectPage(page, new LambdaQueryWrapper<SysAdministrativeAreaDictInfoEntity>());
return this.baseMapper.selectPage(page, new LambdaQueryWrapper<>());
}
/**

View File

@@ -0,0 +1,78 @@
package com.starry.admin.modules.weichat.controller;
import cn.hutool.crypto.SecureUtil;
import com.google.common.annotations.VisibleForTesting;
import com.starry.admin.common.aspect.ClerkUserLogin;
import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.clear.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clear.service.impl.PlayClerkUserInfoServiceImpl;
import com.starry.admin.modules.weichat.entity.PlayClerkUserAddVo;
import com.starry.admin.modules.weichat.entity.PlayClerkUserBindCodeVo;
import com.starry.admin.modules.weichat.entity.PlayClerkUserSendCodeVo;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.redis.RedisCache;
import com.starry.common.result.R;
import com.starry.common.utils.VerificationCodeUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.concurrent.TimeUnit;
/**
* @author admin
*/
@Slf4j
@RestController
@RequestMapping("/wx/clerk/")
public class WxClerkController {
@Resource
RedisCache redisCache;
@Resource
private PlayClerkUserInfoServiceImpl playClerkUserInfoService;
@ClerkUserLogin
@PostMapping("/user/sendCode")
public R sendCode(@VisibleForTesting @RequestBody PlayClerkUserSendCodeVo vo) {
String codeKey = "login_codes:" + SecurityUtils.getTenantId() + "_" + SecureUtil.md5(vo.getAreaCode() + vo.getPhone());
String code = VerificationCodeUtils.getVerificationCode(4);
redisCache.setCacheObject(codeKey, code, 5L, TimeUnit.MINUTES);
// 发送验证码,
return R.ok(code);
}
@ClerkUserLogin
@PostMapping("/user/bindCode")
public R bindCode(@VisibleForTesting @RequestBody PlayClerkUserBindCodeVo vo) {
String codeKey = "login_codes:" + SecurityUtils.getTenantId() + "_" + SecureUtil.md5(vo.getAreaCode() + vo.getPhone());
String code = redisCache.getCacheObject(codeKey);
if (code == null || !code.equals(vo.getCode())) {
throw new CustomException("验证码错误");
}
redisCache.deleteObject(codeKey);
// 账号绑定操作
return R.ok("成功");
}
@ClerkUserLogin
@PostMapping("/user/add")
public R userAdd(@Valid @RequestBody PlayClerkUserAddVo vo) {
PlayClerkUserInfoEntity entity = ThreadLocalRequestDetail.getClerkUserInfo();
BeanUtils.copyProperties(vo, entity);
entity.setPlayUserId("0001");
playClerkUserInfoService.update(entity);
return R.ok("申请成功");
}
}

View File

@@ -0,0 +1,29 @@
package com.starry.admin.modules.weichat.controller;
import com.starry.admin.modules.system.service.ISysAdministrativeAreaDictInfoService;
import com.starry.common.result.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 16:18
**/
@Slf4j
@RestController
@RequestMapping("/wx/common/")
public class WxCommonController {
@Resource
private ISysAdministrativeAreaDictInfoService areaDictInfoService;
@GetMapping("area/tree")
public R list() {
return R.ok(areaDictInfoService.selectTree("2"));
}
}

View File

@@ -1,5 +1,6 @@
package com.starry.admin.modules.weichat.controller;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSONObject;
@@ -14,6 +15,7 @@ import com.starry.admin.modules.weichat.entity.WxUserLoginVo;
import com.starry.admin.modules.weichat.entity.WxUserQueryAddressVo;
import com.starry.admin.modules.weichat.service.WxOauthService;
import com.starry.admin.modules.weichat.service.WxTokenService;
import com.starry.admin.utils.SecurityUtils;
import com.starry.common.result.R;
import lombok.extern.slf4j.Slf4j;
import me.chanjar.weixin.mp.api.WxMpService;
@@ -53,7 +55,7 @@ public class WxOauthController {
private WxOauthService wxOauthService;
@GetMapping("/getClerkLoginAddress")
@PostMapping("/getClerkLoginAddress")
public R getClerkLoginAddress(@RequestBody WxUserQueryAddressVo vo) {
// 默认回调地址
String defaultAddress = "http://july.hucs.top/api/wx/oauth2/clerkLoginCallback";
@@ -70,19 +72,32 @@ public class WxOauthController {
}
@GetMapping("/clark/login")
@PostMapping("/clark/login")
public R clerkLogin(@Valid @RequestBody WxUserLoginVo vo) {
String userId = wxOauthService.clarkUserLogin(vo.getCode());
PlayClerkUserInfoEntity entity = clerkUserInfoService.selectPlayClerkUserInfoById(userId);
PlayClerkUserInfoEntity entity = clerkUserInfoService.selectById(userId);
// 线程塞入租户ID
SecurityUtils.setTenantId(Convert.toStr(entity.getTenantId()));
JSONObject jsonObject = JSONObject.from(entity);
String tokenForMiniUser = tokenService.createMiniUserToken(entity.getId());
String tokenForMiniUser = tokenService.createWxUserToken(entity.getId());
jsonObject.put("tokenValue", TOKEN_PREFIX + tokenForMiniUser);
jsonObject.put("tokenName", CLERK_USER_LOGIN_TOKEN);
jsonObject.put("accountRole", "user");
jsonObject.put("loginDate", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
return R.ok(jsonObject);
}
@PostMapping("/clark/loginById")
public R loginById(@Valid @RequestBody WxUserLoginVo vo) {
PlayClerkUserInfoEntity entity = clerkUserInfoService.selectById(vo.getCode());
JSONObject jsonObject = JSONObject.from(entity);
String tokenValue = tokenService.createWxUserToken(entity.getId());
jsonObject.put("tokenValue", tokenValue);
jsonObject.put("tokenName", TOKEN_PREFIX + CLERK_USER_LOGIN_TOKEN);
jsonObject.put("loginDate", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
clerkUserInfoService.updateTokenById(entity.getId(), tokenValue);
return R.ok(jsonObject);
}
@ClerkUserLogin
@GetMapping("/clark/logout")
public R clerkLogout() {
@@ -91,7 +106,7 @@ public class WxOauthController {
}
@GetMapping("/getCustomLoginAddress")
@PostMapping("/getCustomLoginAddress")
public R getCustomLoginAddress(@RequestBody WxUserQueryAddressVo vo) {
// 默认回调地址
String defaultAddress = "http://july.hucs.top/api/wx/oauth2/customLoginCallback";
@@ -108,23 +123,23 @@ public class WxOauthController {
}
@GetMapping("/custom/login")
@PostMapping("/custom/login")
public R customLogin(@Valid @RequestBody WxUserLoginVo vo) {
String userId = wxOauthService.customUserLogin(vo.getCode());
PlayCustomUserInfoEntity entity = customUserInfoService.selectPlayCustomUserInfoById(userId);
PlayCustomUserInfoEntity entity = customUserInfoService.selectById(userId);
JSONObject jsonObject = JSONObject.from(entity);
String tokenForMiniUser = tokenService.createMiniUserToken(entity.getId());
jsonObject.put("tokenValue", TOKEN_PREFIX + tokenForMiniUser);
String tokenValue = tokenService.createWxUserToken(entity.getId());
jsonObject.put("tokenValue", TOKEN_PREFIX + tokenValue);
jsonObject.put("tokenName", CUSTOM_USER_LOGIN_TOKEN);
jsonObject.put("accountRole", "user");
jsonObject.put("loginDate", DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss"));
customUserInfoService.updateTokenById(entity.getId(), tokenValue);
return R.ok(jsonObject);
}
@GetMapping("/custom/logout")
@CustomUserLogin
public R customLogout(@Valid @RequestBody WxUserLoginVo vo) {
public R customLogout() {
wxOauthService.customUserLogout(ThreadLocalRequestDetail.getCustomUserInfo());
return R.ok("登出成功");
}

View File

@@ -0,0 +1,92 @@
package com.starry.admin.modules.weichat.entity;
import lombok.Data;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
/**
* @author admin
*/
@Data
public class PlayClerkUserAddVo {
/**
* 店员昵称
*/
@NotBlank(message = "昵称不能为空")
private String nickname;
/**
* 店员等级
*/
@NotBlank(message = "等级不能为空")
private String levelId;
/**
* 店员性别10
*/
@NotNull(message = "性别不能为空")
private Integer sex;
/**
* 头像
*/
@NotBlank(message = "头像不能为空")
private String avatar;
/**
* 音频
*/
@NotBlank(message = "音频不能为空")
private String audioFrequency;
/**
* 星座
*/
@NotBlank(message = "星座不能为空")
private String constellation;
/**
* 标签
*/
private String label;
/**
* 个性签名
*/
@NotBlank(message = "签名不能为空")
private String signature;
/**
* 年龄
*/
@NotNull(message = "年龄不能为空")
private Long age;
/**
* 所在国家
*/
@NotBlank(message = "国家不能为空")
private String country;
/**
* 所在省份
*/
@NotBlank(message = "省份不能为空")
private String province;
/**
* 所在城市
*/
@NotBlank(message = "城市不能为空")
private String city;
/**
* 备注
*/
private String remark;
}

View File

@@ -0,0 +1,34 @@
package com.starry.admin.modules.weichat.entity;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author admin
*/
@Data
public class PlayClerkUserBindCodeVo {
/**
* 手机号码区号
*/
@NotBlank(message = "手机号码区号不能为空")
private String areaCode;
/**
* 手机号码
*/
@NotBlank(message = "手机号码不能为空")
private String phone;
/**
* 手机号码
*/
@NotBlank(message = "验证码不能为空")
private String code;
}

View File

@@ -0,0 +1,27 @@
package com.starry.admin.modules.weichat.entity;
import lombok.Data;
import javax.validation.constraints.NotBlank;
/**
* @author admin
*/
@Data
public class PlayClerkUserSendCodeVo {
/**
* 手机号码区号
*/
@NotBlank(message = "手机号码区号不能为空")
private String areaCode;
/**
* 手机号码
*/
@NotBlank(message = "手机号码不能为空")
private String phone;
}

View File

@@ -1,16 +0,0 @@
package com.starry.admin.modules.weichat.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.starry.admin.modules.weichat.entity.PlayWxUserInfoEntity;
/**
* 微信用户Mapper接口
*
* @author admin
* @since 2024-04-07
*/
public interface PlayWxUserInfoMapper extends BaseMapper<PlayWxUserInfoEntity> {
}

View File

@@ -88,7 +88,7 @@ public class Constants
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
public static final String LOGIN_USER_KEY_MINI = "login_user_key_mini";
public static final String LOGIN_USER_KEY_WX = "login_user_key_wx";
public static final String LOGIN_USER_KEY_COSER = "login_user_key_coser";
/**

View File

@@ -3,7 +3,7 @@ package com.starry.admin.modules.weichat.service;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.common.exception.ServiceException;
import com.starry.admin.modules.clear.module.entity.PlayClerkUserInfoEntity;
import com.starry.admin.modules.clear.service.IPlayClerkUserInfoService;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
@@ -72,8 +72,7 @@ public class WxOauthService {
WxOAuth2AccessToken token = getWxOAuth2AccessToken(code);
String openId = getOpenId(token);
WxOAuth2UserInfo userInfo = getWxOAuth2UserInfo(token);
PlayCustomUserInfoEntity entity = new PlayCustomUserInfoEntity();
ConvertUtil.entityToVo(userInfo, PlayClerkUserInfoEntity.class);
PlayCustomUserInfoEntity entity = ConvertUtil.entityToVo(userInfo, PlayCustomUserInfoEntity.class);
entity.setAvatar(userInfo.getHeadImgUrl());
PlayCustomUserInfoEntity item = customUserInfoService.selectByOpenid(openId);
entity.setId(item != null ? item.getId() : IdUtil.fastSimpleUUID());
@@ -92,7 +91,7 @@ public class WxOauthService {
**/
public WxOAuth2AccessToken getWxOAuth2AccessToken(String code) {
if (StrUtil.isBlankIfStr(code)) {
throw new CustomException("不能为空");
throw new ServiceException("不能为空");
}
synchronized (code.intern()) {
try {
@@ -113,11 +112,11 @@ public class WxOauthService {
**/
public String getOpenId(WxOAuth2AccessToken token) {
if (token == null) {
throw new CustomException("获取微信授权异常WxOAuth2AccessToken不能为空");
throw new ServiceException("获取微信授权异常WxOAuth2AccessToken不能为空");
}
String openId = token.getOpenId();
if (StrUtil.isBlankIfStr(openId)) {
throw new CustomException("获取微信授权异常openId不能为空");
throw new ServiceException("获取微信授权异常openId不能为空");
}
return openId;
}
@@ -132,7 +131,7 @@ public class WxOauthService {
**/
public WxOAuth2UserInfo getWxOAuth2UserInfo(WxOAuth2AccessToken token) {
if (token == null) {
throw new CustomException("获取微信授权异常WxOAuth2AccessToken不能为空");
throw new ServiceException("获取微信授权异常WxOAuth2AccessToken不能为空");
}
try {
return wxMpService.getOAuth2Service().getUserInfo(token, null);

View File

@@ -22,104 +22,95 @@ import java.util.Objects;
@Slf4j
@Service
public class WxTokenService {
// 令牌自定义标识
/**
* 令牌自定义标识
*
* @since 2024/4/10 11:20
**/
@Value("${token.header}")
private String header;
// 令牌秘钥
/**
* 令牌秘钥
*
* @since 2024/4/10 11:20
**/
@Value("${token.secret}")
private String secret;
// 令牌有效期默认30分钟
/**
* 令牌有效期默认30分钟
*
* @since 2024/4/10 11:20
**/
@Value("${token.expireTime}")
private int expireTime;
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
//
// @Autowired
// private RedisCache redisCache;
// /**
// * 获取用户身份信息
// *
// * @return 用户信息
// */
// public LoginUser getLoginUser(HttpServletRequest request) {
// // 获取请求携带的令牌
// String token = getToken(request);
// if (StringUtils.isNotEmpty(token)) {
// try {
// Claims claims = parseToken(token);
// // 解析对应的权限以及用户信息
// String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
// String userKey = getTokenKey(uuid);
// LoginUser user = redisCache.getCacheObject(userKey);
// return user;
// } catch (Exception e) {
// }
// }
// return null;
// }
//
//
// /**
// * 设置用户身份信息
// */
// public void setLoginUser(LoginUser loginUser) {
// if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken())) {
// refreshToken(loginUser);
// }
// }
//
// /**
// * 删除用户身份信息
// */
// public void delLoginUser(String token) {
// if (StringUtils.isNotEmpty(token)) {
// String userKey = getTokenKey(token);
// redisCache.deleteObject(userKey);
// }
// }
//
// /**
// * 创建令牌
// *
// * @param loginUser 用户信息
// * @return 令牌
// */
// public String createToken(LoginUser loginUser) {
// String token = IdUtils.fastUUID();
// loginUser.setToken(token);
// setUserAgent(loginUser);
// refreshToken(loginUser);
//
// Map<String, Object> claims = new HashMap<>();
// claims.put(Constants.LOGIN_USER_KEY, token);
// return createToken(claims);
// }
// 小程序端-委托人
public String createMiniUserToken(String miniUserId) {
if (Objects.isNull(miniUserId)) {
/**
* 根据微信用户id创建token
*
* @param userId 微信用户ID
* @return String token
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 11:21
**/
public String createWxUserToken(String userId) {
if (Objects.isNull(userId)) {
throw new RuntimeException("用户id不能为空");
}
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY_MINI, miniUserId);
Map<String, Object> claims = new HashMap<>(16);
claims.put(Constants.LOGIN_USER_KEY_WX, userId);
return Jwts.builder().setClaims(claims).setExpiration(DateUtil.offsetMinute(new Date(), expireTime)).signWith(SignatureAlgorithm.HS512, secret).compact();
}
// 小程序端-委托人
public String getMiniUserIdByToken(String token) {
/**
* 根据token获取微信用户ID
*
* @param token token
* @return String 微信用户ID
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 11:24
**/
public String getWxUserIdByToken(String token) {
if (StringUtils.isEmpty(token)) {
throw new RuntimeException("token不能为空");
}
Claims claims = parseToken(token);
return claims.get(Constants.LOGIN_USER_KEY_MINI).toString();
return claims.get(Constants.LOGIN_USER_KEY_WX).toString();
}
/**
* 根据token获取微信用户TenantId
*
* @param token token
* @param identity 用户身份0:租户1:顾客)
* @return String 微信用户租户ID
* @author 杭州世平信息科技有限公司-xuhq
* @since 2024/4/10 11:24
**/
public String getWxUserTenantIdByToken(String token, String identity) {
if (StringUtils.isEmpty(token)) {
throw new RuntimeException("token不能为空");
}
Claims claims = parseToken(token);
return claims.get(Constants.LOGIN_USER_KEY_WX).toString();
}
// public String getTenantId(String token) {
// if (StringUtils.isEmpty(token)) {
// throw new RuntimeException("token不能为空");
// }
// Map<String, Object> claims = new HashMap<>();
// claims.put(Constants.LOGIN_USER_KEY_MINI, miniUserId);
// return Jwts.builder().setClaims(claims).setExpiration(DateUtil.offsetMinute(new Date(), expireTime)).signWith(SignatureAlgorithm.HS512, secret).compact();
// }
//
// // 小程序端-coser
// public String createMiniCoserToken(Long miniCoserId) {

View File

@@ -92,8 +92,8 @@ token:
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期默认30分钟
expireTime: 43200
# 令牌有效期,单位分钟默认30分钟
expireTime: 129600
# xl自定义配置
xl: