新增TokenIgnore注解,完善User模块

This commit is contained in:
COOL
2024-07-23 14:55:52 +08:00
parent e08c0cc1f5
commit 12ac71e93f
18 changed files with 419 additions and 82 deletions
@@ -2,6 +2,7 @@ package com.cool.modules.base.controller.admin;
import cn.hutool.core.lang.Dict;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.annotation.TokenIgnore;
import com.cool.core.eps.CoolEps;
import com.cool.core.file.FileUploadStrategyFactory;
import com.cool.core.request.R;
@@ -40,6 +41,7 @@ public class AdminBaseCommController {
final private FileUploadStrategyFactory fileUploadStrategyFactory;
@TokenIgnore
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
@@ -1,6 +1,7 @@
package com.cool.modules.base.controller.app;
import com.cool.core.annotation.CoolRestController;
import com.cool.core.annotation.TokenIgnore;
import com.cool.core.eps.CoolEps;
import com.cool.core.request.R;
import io.swagger.v3.oas.annotations.Operation;
@@ -18,6 +19,7 @@ public class AppBaseCommController {
final private CoolEps coolEps;
@TokenIgnore
@Operation(summary = "实体信息与路径", description = "系统所有的实体信息与路径,供前端自动生成代码与服务")
@GetMapping("/eps")
public R eps() {
@@ -3,6 +3,7 @@ package com.cool.modules.base.security;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.cool.core.annotation.TokenIgnore;
import com.cool.core.cache.CoolCache;
import com.cool.core.security.jwt.JwtTokenUtil;
import com.cool.core.security.jwt.JwtUser;
@@ -10,8 +11,10 @@ import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Objects;
import lombok.RequiredArgsConstructor;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
@@ -20,6 +23,9 @@ import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerExecutionChain;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
/**
* Token过滤器
@@ -31,28 +37,46 @@ public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
final private JwtTokenUtil jwtTokenUtil;
final private CoolCache coolCache;
private final RequestMappingHandlerMapping handlerMapping;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
FilterChain chain)
throws ServletException, IOException {
FilterChain chain)
throws ServletException, IOException {
try {
HandlerExecutionChain handlerExecutionChain = handlerMapping.getHandler(request);
if (handlerExecutionChain != null) {
Object handler = handlerExecutionChain.getHandler();
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod.getMethodAnnotation(TokenIgnore.class) != null ||
handlerMethod.getBeanType().getAnnotation(TokenIgnore.class) != null) {
chain.doFilter(request, response);
return;
}
}
}
} catch (Exception e) {
throw new RuntimeException(e);
}
String authToken = request.getHeader("Authorization");
if (!StrUtil.isEmpty(authToken)) {
JWT jwt = jwtTokenUtil.getTokenInfo(authToken);
String username = jwt.getPayload("username").toString();
if (username != null
&& SecurityContextHolder.getContext().getAuthentication() == null) {
&& SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = coolCache.get("admin:userDetails:" + username,
JwtUser.class);
JwtUser.class);
Integer passwordV = Convert.toInt(jwt.getPayload("passwordVersion"));
Integer rv = coolCache.get("admin:passwordVersion:" + jwt.getPayload("userId"),
Integer.class);
Integer.class);
if (jwtTokenUtil.validateToken(authToken, username) && Objects.equals(passwordV, rv)
&& userDetails != null) {
&& userDetails != null) {
UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
userDetails, null, userDetails.getAuthorities());
authentication.setDetails(
new WebAuthenticationDetailsSource().buildDetails(request));
new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
request.setAttribute("adminUsername", jwt.getPayload("username"));
request.setAttribute("adminUserId", jwt.getPayload("userId"));
@@ -0,0 +1,23 @@
package com.cool.modules.user.controller.app;
import com.cool.core.annotation.CoolRestController;
import com.cool.modules.user.service.UserInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestAttribute;
@RequiredArgsConstructor
@Tag(name = "用户信息", description = "用户信息")
@CoolRestController()
public class AppUserInfoController {
private final UserInfoService userInfoService;
@Operation(summary = "用户个人信息", description = "获得App、小程序或者其他应用的用户个人信息")
@GetMapping("/person")
public Object person(@RequestAttribute("appUserId") Long appUserId) {
return userInfoService.person(appUserId);
}
}
@@ -4,4 +4,10 @@ import com.cool.core.base.BaseService;
import com.cool.modules.user.entity.UserInfoEntity;
public interface UserInfoService extends BaseService<UserInfoEntity> {
/**
* 用户个人信息
* @param userId
* @return
*/
Object person(Long userId);
}
@@ -0,0 +1,31 @@
package com.cool.modules.user.service;
/**
* 用户登录
*/
public interface UserLoginService {
/**
* 发送短信验证码
* @param phone
* @param captchaId
* @param code
*/
void smsCode(String phone, String captchaId, String code);
/**
* 手机号验证码登录
* @param phone
* @param smsCode
*/
Object phoneVerifyCode(String phone, String smsCode);
/**
* 刷新token
*
* @param refreshToken 刷新token
* @return 新的token
*/
Object refreshToken(String refreshToken);
}
@@ -10,4 +10,10 @@ import org.springframework.stereotype.Service;
public class UserInfoServiceImpl extends BaseServiceImpl<UserInfoMapper, UserInfoEntity> implements
UserInfoService {
@Override
public Object person(Long userId) {
UserInfoEntity info = mapper.selectOneById(userId);
info.setPassword(null);
return info;
}
}
@@ -0,0 +1,65 @@
package com.cool.modules.user.service.impl;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Dict;
import cn.hutool.jwt.JWT;
import com.cool.core.cache.CoolCache;
import com.cool.core.exception.CoolException;
import com.cool.core.exception.CoolPreconditions;
import com.cool.core.security.jwt.JwtTokenUtil;
import com.cool.modules.base.security.CoolSecurityUtil;
import com.cool.modules.user.entity.UserInfoEntity;
import com.cool.modules.user.mapper.UserInfoMapper;
import com.cool.modules.user.service.UserLoginService;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Service
public class UserLoginServiceImpl implements UserLoginService {
private final CoolCache coolCache;
private final AuthenticationManager authenticationManager;
private final CoolSecurityUtil coolSecurityUtil;
private final JwtTokenUtil jwtTokenUtil;
private final UserInfoMapper userInfoMapper;
@Override
public void smsCode(String phone, String captchaId, String code) {
}
@Override
public Object phoneVerifyCode(String phone, String smsCode) {
return null;
}
@Override
public Object refreshToken(String refreshToken) {
JWT jwt = jwtTokenUtil.getTokenInfo(refreshToken);
try {
CoolPreconditions.check(jwt == null || !(Boolean) jwt.getPayload("isRefresh"),
"错误的token");
UserInfoEntity userInfoEntity =
userInfoMapper.selectOneById(Convert.toLong(jwt.getPayload("userId")));
Dict tokenInfo =
Dict.create()
.set("userId", userInfoEntity.getId());
String token = jwtTokenUtil.generateToken(tokenInfo);
refreshToken = jwtTokenUtil.generateRefreshToken(tokenInfo);
return Dict.create()
.set("token", token)
.set("expire", jwtTokenUtil.getExpire())
.set("refreshToken", refreshToken)
.set("refreshExpire", jwtTokenUtil.getRefreshExpire());
} catch (Exception e) {
throw new CoolException("错误的token", e);
}
}
}
@@ -0,0 +1,53 @@
package com.cool.modules.user.token;
import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.cool.core.annotation.TokenIgnore;
import com.cool.core.security.jwt.JwtTokenUtil;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
/**
* 用户Token拦截器
*/
@Slf4j
@RequiredArgsConstructor
@Component
public class UserTokenInterceptor implements HandlerInterceptor {
private final JwtTokenUtil jwtTokenUtil;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 检查是否有 TokenIgnore 注解,有则跳过
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
if (handlerMethod.getMethodAnnotation(TokenIgnore.class) != null ||
handlerMethod.getBeanType().getAnnotation(TokenIgnore.class) != null) {
return true;
}
}
String token = request.getHeader("Authorization");
if (StrUtil.isNotEmpty(token)) {
try {
if (jwtTokenUtil.validateToken(token)) {
JWT jwt = jwtTokenUtil.getTokenInfo(token);
String userId = jwt.getPayload("userId").toString();
request.setAttribute("appUserId", userId);
return true;
}
} catch (Exception e) {
// Logging can be added here if needed
log.error("Invalid Token", e);
}
}
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("Invalid Token");
return false;
}
}
@@ -0,0 +1,21 @@
package com.cool.modules.user.token;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* 用户Web配置
*/
@RequiredArgsConstructor
@Configuration
public class UserWebConfig implements WebMvcConfigurer {
final private UserTokenInterceptor userTokenInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userTokenInterceptor)
.addPathPatterns("/app/**");
}
}
@@ -0,0 +1,78 @@
package com.cool.modules.user.util;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import com.cool.core.cache.CoolCache;
import com.cool.core.plugin.service.CoolPluginService;
import com.cool.core.util.CoolPluginInvokers;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* UserSmsUtil - 用户短信工具类
* 该类用于发送短信验证码。
*/
@RequiredArgsConstructor
@Slf4j
@Component
public class UserSmsUtil {
private final CoolPluginService coolPluginService;
private final CoolCache coolCache;
/**
* 发送短信验证码
*
* @param phone
* @param code
*/
void sendVerifyCode(String phone, String code) {
// 随机生成4位验证码
String verifyCode = RandomUtil.randomNumbers(4);
send(phone, verifyCode);
coolCache.set("sms:" + phone, verifyCode, 60 * 10);
}
/**
* 检查验证码
* @param phone
* @param code
* @return
*/
boolean checkVerifyCode(String phone, String code) {
String cacheCode = coolCache.get("sms:" + phone, String.class);
return StrUtil.isNotEmpty(code) && code.equals(cacheCode);
}
/**
* 发送短信
*
* @param phone
* @param code
*/
void send(String phone, String code) {
List<String> phones = new ArrayList<>();
phones.add("xxx");
Map<String, Object> params = new HashMap<>();
params.put("code", code);
// 插件key sms-tx、sms-ali,哪个实例存在就调用哪个
if (coolPluginService.getInstance("sms-tx") != null) {
// 调用腾讯短信插件
} else if (coolPluginService.getInstance("sms-ali") != null) {
// 调用阿里短信插件
CoolPluginInvokers.invoke("sms-ali", "send", phones, params);
} else {
// 未找到短信插件
log.error("未找到短信插件,请前往插件市场下载安装");
}
}
}
@@ -0,0 +1,12 @@
package com.cool.modules.user.util;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
/**
* UserWxUtil - 用户微信工具类
*/
@Component
@RequiredArgsConstructor
public class UserWxUtil {
}