权限管理
This commit is contained in:
parent
04cfab2f82
commit
48fb1db044
@ -20,6 +20,8 @@ public interface SecurityConstant {
|
|||||||
*/
|
*/
|
||||||
String HEADER = "accessToken";
|
String HEADER = "accessToken";
|
||||||
|
|
||||||
|
String ATTRIBUTE_APP_USER = "ATTRIBUTE_APP_USER";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 权限参数头
|
* 权限参数头
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -1,8 +1,13 @@
|
|||||||
package com.sunyard.chsm.mapper;
|
package com.sunyard.chsm.mapper;
|
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||||
import com.sunyard.chsm.model.entity.CryptoServiceApi;
|
import com.sunyard.chsm.model.entity.CryptoServiceApi;
|
||||||
import org.apache.ibatis.annotations.Mapper;
|
import org.apache.ibatis.annotations.Mapper;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@ -10,4 +15,17 @@ import org.apache.ibatis.annotations.Mapper;
|
|||||||
*/
|
*/
|
||||||
@Mapper
|
@Mapper
|
||||||
public interface CryptoServiceApiMapper extends BaseMapper<CryptoServiceApi> {
|
public interface CryptoServiceApiMapper extends BaseMapper<CryptoServiceApi> {
|
||||||
|
|
||||||
|
default List<CryptoServiceApi> selectByServiceIds(List<Long> serviceIds) {
|
||||||
|
if (CollectionUtils.isEmpty(serviceIds)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
return selectList(
|
||||||
|
new LambdaQueryWrapper<CryptoServiceApi>()
|
||||||
|
.in(CryptoServiceApi::getCryptoServiceId, serviceIds)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -49,13 +49,15 @@
|
|||||||
<groupId>com.dm</groupId>
|
<groupId>com.dm</groupId>
|
||||||
<artifactId>DmJdbcDriver</artifactId>
|
<artifactId>DmJdbcDriver</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- JWT -->
|
<!-- JWT -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>io.jsonwebtoken</groupId>
|
<groupId>io.jsonwebtoken</groupId>
|
||||||
<artifactId>jjwt</artifactId>
|
<artifactId>jjwt</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
<artifactId>caffeine</artifactId>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -22,6 +22,8 @@ import java.util.Arrays;
|
|||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
|
|
||||||
|
import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @version V1.0
|
* @version V1.0
|
||||||
@ -56,7 +58,7 @@ public class AppTokenFilter extends OncePerRequestFilter {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
AppUser user = appLoginService.verifyToken(tokenValue);
|
AppUser user = appLoginService.verifyToken(tokenValue);
|
||||||
request.setAttribute("APP_USER", user);
|
request.setAttribute(ATTRIBUTE_APP_USER, user);
|
||||||
filterChain.doFilter(request, response);
|
filterChain.doFilter(request, response);
|
||||||
} catch (ExpiredJwtException ex) {
|
} catch (ExpiredJwtException ex) {
|
||||||
log.warn("token已过期: {}", requestURI);
|
log.warn("token已过期: {}", requestURI);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import java.util.List;
|
|||||||
@Data
|
@Data
|
||||||
public class AppUser {
|
public class AppUser {
|
||||||
|
|
||||||
|
private String tokenId;
|
||||||
private Long appId;
|
private Long appId;
|
||||||
private String name;
|
private String name;
|
||||||
private List<Long> serviceIds;
|
private List<Long> serviceIds;
|
||||||
|
|||||||
@ -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 "";
|
||||||
|
}
|
||||||
@ -1,22 +1,85 @@
|
|||||||
package com.sunyard.chsm.auth;
|
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 org.springframework.web.servlet.HandlerInterceptor;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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
|
* @author liulu
|
||||||
* @since 2024/11/13
|
* @since 2024/11/13
|
||||||
*/
|
*/
|
||||||
public class AuthHandler implements HandlerInterceptor {
|
@Slf4j
|
||||||
|
@Component
|
||||||
|
public class AuthHandler implements HandlerInterceptor, InitializingBean {
|
||||||
|
|
||||||
|
Cache<String, Map<String, List<Long>>> cache = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* token 过期时间, 分钟
|
||||||
|
*/
|
||||||
|
@Value("${chsm.token.expireTime:720}")
|
||||||
|
private Integer tokenExpireTime;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private CryptoServiceApiMapper cryptoServiceApiMapper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
|
||||||
|
if (!(handler instanceof HandlerMethod)) {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return true;
|
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<String, List<Long>> codeServiceMap = cache.get(user.getTokenId(), k -> {
|
||||||
|
List<CryptoServiceApi> 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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,8 @@ package com.sunyard.chsm.auth;
|
|||||||
import org.springframework.web.context.request.RequestAttributes;
|
import org.springframework.web.context.request.RequestAttributes;
|
||||||
import org.springframework.web.context.request.RequestContextHolder;
|
import org.springframework.web.context.request.RequestContextHolder;
|
||||||
|
|
||||||
|
import static com.sunyard.chsm.constant.SecurityConstant.ATTRIBUTE_APP_USER;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
* @since 2024/12/6
|
* @since 2024/12/6
|
||||||
@ -12,7 +14,7 @@ public class UserContext {
|
|||||||
|
|
||||||
public static AppUser getCurrentUser() {
|
public static AppUser getCurrentUser() {
|
||||||
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
|
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
|
||||||
return (AppUser) requestAttributes.getAttribute("APP_USER", RequestAttributes.SCOPE_REQUEST);
|
return (AppUser) requestAttributes.getAttribute(ATTRIBUTE_APP_USER, RequestAttributes.SCOPE_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -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("/**");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@ -1,5 +1,6 @@
|
|||||||
package com.sunyard.chsm.controller;
|
package com.sunyard.chsm.controller;
|
||||||
|
|
||||||
|
import com.sunyard.chsm.auth.AuthCode;
|
||||||
import com.sunyard.chsm.model.R;
|
import com.sunyard.chsm.model.R;
|
||||||
import com.sunyard.chsm.model.dto.KeyInfoDTO;
|
import com.sunyard.chsm.model.dto.KeyInfoDTO;
|
||||||
import com.sunyard.chsm.service.KeyInfoService;
|
import com.sunyard.chsm.service.KeyInfoService;
|
||||||
@ -31,6 +32,7 @@ public class KeyManageController {
|
|||||||
* @return id
|
* @return id
|
||||||
*/
|
*/
|
||||||
@PostMapping("/enable")
|
@PostMapping("/enable")
|
||||||
|
@AuthCode("12312312")
|
||||||
public R<Void> enableKey(@Validated @RequestBody KeyInfoDTO.IDs param) {
|
public R<Void> enableKey(@Validated @RequestBody KeyInfoDTO.IDs param) {
|
||||||
keyInfoService.enableKey(param.getIds());
|
keyInfoService.enableKey(param.getIds());
|
||||||
return R.ok();
|
return R.ok();
|
||||||
|
|||||||
@ -3,7 +3,9 @@ package com.sunyard.chsm.service;
|
|||||||
import com.sunyard.chsm.auth.AppUser;
|
import com.sunyard.chsm.auth.AppUser;
|
||||||
import com.sunyard.chsm.constant.SecurityConstant;
|
import com.sunyard.chsm.constant.SecurityConstant;
|
||||||
import com.sunyard.chsm.enums.EnableStatus;
|
import com.sunyard.chsm.enums.EnableStatus;
|
||||||
|
import com.sunyard.chsm.mapper.AppServiceMapper;
|
||||||
import com.sunyard.chsm.mapper.ApplicationMapper;
|
import com.sunyard.chsm.mapper.ApplicationMapper;
|
||||||
|
import com.sunyard.chsm.model.entity.AppService;
|
||||||
import com.sunyard.chsm.model.entity.Application;
|
import com.sunyard.chsm.model.entity.Application;
|
||||||
import com.sunyard.chsm.param.AppTokenReq;
|
import com.sunyard.chsm.param.AppTokenReq;
|
||||||
import com.sunyard.chsm.param.AppTokenResp;
|
import com.sunyard.chsm.param.AppTokenResp;
|
||||||
@ -27,6 +29,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author liulu
|
* @author liulu
|
||||||
@ -43,6 +46,8 @@ public class AppLoginService {
|
|||||||
private Integer tokenExpireTime;
|
private Integer tokenExpireTime;
|
||||||
@Resource
|
@Resource
|
||||||
private ApplicationMapper applicationMapper;
|
private ApplicationMapper applicationMapper;
|
||||||
|
@Resource
|
||||||
|
private AppServiceMapper appServiceMapper;
|
||||||
|
|
||||||
public AppTokenResp getAppToken(AppTokenReq req) {
|
public AppTokenResp getAppToken(AppTokenReq req) {
|
||||||
Long random = req.getRandom();
|
Long random = req.getRandom();
|
||||||
@ -64,10 +69,12 @@ public class AppLoginService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private String genToken(Application app) {
|
private String genToken(Application app) {
|
||||||
|
List<AppService> appServices = appServiceMapper.selectByAppIds(Collections.singletonList(app.getId()));
|
||||||
|
List<Long> serviceIds = appServices.stream().map(AppService::getServiceId).collect(Collectors.toList());
|
||||||
Map<String, Object> claims = new HashMap<>();
|
Map<String, Object> claims = new HashMap<>();
|
||||||
claims.put("appId", app.getId());
|
claims.put("appId", app.getId());
|
||||||
claims.put("name", app.getName());
|
claims.put("name", app.getName());
|
||||||
claims.put("serviceIds", Collections.singletonList(app.getId()));
|
claims.put("serviceIds", serviceIds);
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
return Jwts.builder()
|
return Jwts.builder()
|
||||||
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
|
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
|
||||||
@ -103,6 +110,7 @@ public class AppLoginService {
|
|||||||
.getBody();
|
.getBody();
|
||||||
|
|
||||||
AppUser user = new AppUser();
|
AppUser user = new AppUser();
|
||||||
|
user.setTokenId(claims.get("jti", String.class));
|
||||||
user.setAppId(claims.get("appId", Long.class));
|
user.setAppId(claims.get("appId", Long.class));
|
||||||
user.setName(claims.get("name", String.class));
|
user.setName(claims.get("name", String.class));
|
||||||
user.setServiceIds(claims.get("serviceIds", List.class));
|
user.setServiceIds(claims.get("serviceIds", List.class));
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user