diff --git a/chsm-common/src/main/java/com/sunyard/chsm/constant/SecurityConstant.java b/chsm-common/src/main/java/com/sunyard/chsm/constant/SecurityConstant.java index a56e248..e1ecc1d 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/constant/SecurityConstant.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/constant/SecurityConstant.java @@ -20,6 +20,8 @@ public interface SecurityConstant { */ String HEADER = "accessToken"; + String ATTRIBUTE_APP_USER = "ATTRIBUTE_APP_USER"; + /** * 权限参数头 */ diff --git a/chsm-common/src/main/java/com/sunyard/chsm/mapper/CryptoServiceApiMapper.java b/chsm-common/src/main/java/com/sunyard/chsm/mapper/CryptoServiceApiMapper.java index 32a169c..2e77e84 100644 --- a/chsm-common/src/main/java/com/sunyard/chsm/mapper/CryptoServiceApiMapper.java +++ b/chsm-common/src/main/java/com/sunyard/chsm/mapper/CryptoServiceApiMapper.java @@ -1,8 +1,13 @@ package com.sunyard.chsm.mapper; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.sunyard.chsm.model.entity.CryptoServiceApi; import org.apache.ibatis.annotations.Mapper; +import org.springframework.util.CollectionUtils; + +import java.util.Collections; +import java.util.List; /** * @author liulu @@ -10,4 +15,17 @@ import org.apache.ibatis.annotations.Mapper; */ @Mapper public interface CryptoServiceApiMapper extends BaseMapper { + + default List selectByServiceIds(List serviceIds) { + if (CollectionUtils.isEmpty(serviceIds)) { + return Collections.emptyList(); + } + return selectList( + new LambdaQueryWrapper() + .in(CryptoServiceApi::getCryptoServiceId, serviceIds) + ); + } + + } + diff --git a/chsm-web-server/pom.xml b/chsm-web-server/pom.xml index dbd0d6a..20d13af 100644 --- a/chsm-web-server/pom.xml +++ b/chsm-web-server/pom.xml @@ -49,13 +49,15 @@ com.dm DmJdbcDriver - io.jsonwebtoken jjwt - + + com.github.ben-manes.caffeine + caffeine + diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java index 9f7ac3c..5453057 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppTokenFilter.java @@ -22,6 +22,8 @@ import java.util.Arrays; import java.util.Collection; import java.util.Enumeration; +import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER; + /** * @author liulu * @version V1.0 @@ -56,7 +58,7 @@ public class AppTokenFilter extends OncePerRequestFilter { try { AppUser user = appLoginService.verifyToken(tokenValue); - request.setAttribute("APP_USER", user); + request.setAttribute(ATTRIBUTE_APP_USER, user); filterChain.doFilter(request, response); } catch (ExpiredJwtException ex) { log.warn("token已过期: {}", requestURI); diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppUser.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppUser.java index d7bfaa0..1f65f65 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppUser.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AppUser.java @@ -11,6 +11,7 @@ import java.util.List; @Data public class AppUser { + private String tokenId; private Long appId; private String name; private List serviceIds; diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthCode.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthCode.java new file mode 100644 index 0000000..3df28b0 --- /dev/null +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthCode.java @@ -0,0 +1,19 @@ +package com.sunyard.chsm.auth; + + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author liulu + * @since 2024/12/6 + */ +@Target({ElementType.METHOD}) +@Retention(RetentionPolicy.RUNTIME) +@Documented +public @interface AuthCode { + String value() default ""; +} diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java index 23c038a..7497756 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/AuthHandler.java @@ -1,22 +1,85 @@ package com.sunyard.chsm.auth; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.sunyard.chsm.mapper.CryptoServiceApiMapper; +import com.sunyard.chsm.model.R; +import com.sunyard.chsm.model.entity.CryptoServiceApi; +import com.sunyard.chsm.utils.JsonUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; +import org.springframework.web.method.HandlerMethod; import org.springframework.web.servlet.HandlerInterceptor; +import javax.annotation.Resource; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import java.time.Duration; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.stream.Collectors; + +import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER; /** * @author liulu * @since 2024/11/13 */ -public class AuthHandler implements HandlerInterceptor { +@Slf4j +@Component +public class AuthHandler implements HandlerInterceptor, InitializingBean { + + Cache>> cache = null; + + /** + * token 过期时间, 分钟 + */ + @Value("${chsm.token.expireTime:720}") + private Integer tokenExpireTime; + + @Resource + private CryptoServiceApiMapper cryptoServiceApiMapper; + @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { + if (!(handler instanceof HandlerMethod)) { + return true; + } + AppUser user = (AppUser) request.getAttribute(ATTRIBUTE_APP_USER); + if (Objects.isNull(user)) { + return true; + } + HandlerMethod handlerMethod = (HandlerMethod) handler; + AuthCode authCode = handlerMethod.getMethodAnnotation(AuthCode.class); + if (authCode == null || ObjectUtils.isEmpty(authCode.value())) { + return true; + } - - - + String code = authCode.value(); + Map> codeServiceMap = cache.get(user.getTokenId(), k -> { + List apis = cryptoServiceApiMapper.selectByServiceIds(user.getServiceIds()); + return apis.stream().collect(Collectors.groupingBy(CryptoServiceApi::getApiCode, + Collectors.mapping(CryptoServiceApi::getCryptoServiceId, Collectors.toList()))); + }); + if (codeServiceMap == null || !codeServiceMap.containsKey(code)) { + log.warn("app: {}-{}, 无权访问: {}", user.getAppId(), user.getName(), request.getRequestURI()); + response.setContentType(MediaType.APPLICATION_JSON_VALUE); + response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("无权访问"))); + return false; + } return true; } + + @Override + public void afterPropertiesSet() throws Exception { + cache = Caffeine.newBuilder() + .expireAfterWrite(Duration.ofMinutes(tokenExpireTime)) + .build(); + } } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/UserContext.java b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/UserContext.java index 889c10c..660ed2d 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/auth/UserContext.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/auth/UserContext.java @@ -3,6 +3,8 @@ package com.sunyard.chsm.auth; import org.springframework.web.context.request.RequestAttributes; import org.springframework.web.context.request.RequestContextHolder; +import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER; + /** * @author liulu * @since 2024/12/6 @@ -12,7 +14,7 @@ public class UserContext { public static AppUser getCurrentUser() { RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes(); - return (AppUser) requestAttributes.getAttribute("APP_USER", RequestAttributes.SCOPE_REQUEST); + return (AppUser) requestAttributes.getAttribute(ATTRIBUTE_APP_USER, RequestAttributes.SCOPE_REQUEST); } diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/config/WebConfig.java b/chsm-web-server/src/main/java/com/sunyard/chsm/config/WebConfig.java new file mode 100644 index 0000000..61d2ecb --- /dev/null +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/config/WebConfig.java @@ -0,0 +1,29 @@ +package com.sunyard.chsm.config; + +import com.sunyard.chsm.auth.AuthHandler; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.InterceptorRegistry; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; + +/** + * @author liulu + * @since 2024/12/6 + */ +@Configuration +public class WebConfig { + + + @Bean + public WebMvcConfigurer webMvcConfigurer(AuthHandler authHandler) { + return new WebMvcConfigurer() { + @Override + public void addInterceptors(InterceptorRegistry registry) { + registry.addInterceptor(authHandler).addPathPatterns("/**"); + } + }; + } + + + +} diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java index db71e36..6ffdfd9 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/controller/KeyManageController.java @@ -1,5 +1,6 @@ package com.sunyard.chsm.controller; +import com.sunyard.chsm.auth.AuthCode; import com.sunyard.chsm.model.R; import com.sunyard.chsm.model.dto.KeyInfoDTO; import com.sunyard.chsm.service.KeyInfoService; @@ -31,6 +32,7 @@ public class KeyManageController { * @return id */ @PostMapping("/enable") + @AuthCode("12312312") public R enableKey(@Validated @RequestBody KeyInfoDTO.IDs param) { keyInfoService.enableKey(param.getIds()); return R.ok(); diff --git a/chsm-web-server/src/main/java/com/sunyard/chsm/service/AppLoginService.java b/chsm-web-server/src/main/java/com/sunyard/chsm/service/AppLoginService.java index d7ab74c..aabfa31 100644 --- a/chsm-web-server/src/main/java/com/sunyard/chsm/service/AppLoginService.java +++ b/chsm-web-server/src/main/java/com/sunyard/chsm/service/AppLoginService.java @@ -3,7 +3,9 @@ package com.sunyard.chsm.service; import com.sunyard.chsm.auth.AppUser; import com.sunyard.chsm.constant.SecurityConstant; import com.sunyard.chsm.enums.EnableStatus; +import com.sunyard.chsm.mapper.AppServiceMapper; import com.sunyard.chsm.mapper.ApplicationMapper; +import com.sunyard.chsm.model.entity.AppService; import com.sunyard.chsm.model.entity.Application; import com.sunyard.chsm.param.AppTokenReq; import com.sunyard.chsm.param.AppTokenResp; @@ -27,6 +29,7 @@ import java.util.List; import java.util.Map; import java.util.Objects; import java.util.UUID; +import java.util.stream.Collectors; /** * @author liulu @@ -43,6 +46,8 @@ public class AppLoginService { private Integer tokenExpireTime; @Resource private ApplicationMapper applicationMapper; + @Resource + private AppServiceMapper appServiceMapper; public AppTokenResp getAppToken(AppTokenReq req) { Long random = req.getRandom(); @@ -64,10 +69,12 @@ public class AppLoginService { } private String genToken(Application app) { + List appServices = appServiceMapper.selectByAppIds(Collections.singletonList(app.getId())); + List serviceIds = appServices.stream().map(AppService::getServiceId).collect(Collectors.toList()); Map claims = new HashMap<>(); claims.put("appId", app.getId()); claims.put("name", app.getName()); - claims.put("serviceIds", Collections.singletonList(app.getId())); + claims.put("serviceIds", serviceIds); Date now = new Date(); return Jwts.builder() .setHeaderParam(Header.TYPE, Header.JWT_TYPE) @@ -103,6 +110,7 @@ public class AppLoginService { .getBody(); AppUser user = new AppUser(); + user.setTokenId(claims.get("jti", String.class)); user.setAppId(claims.get("appId", Long.class)); user.setName(claims.get("name", String.class)); user.setServiceIds(claims.get("serviceIds", List.class));