设备和token
This commit is contained in:
parent
bcf8dfb5f3
commit
04cfab2f82
@ -1,4 +1,4 @@
|
||||
package com.sunyard.ssp.common.constant;
|
||||
package com.sunyard.chsm.constant;
|
||||
|
||||
/**
|
||||
* @author Exrickx
|
@ -14,7 +14,7 @@ import java.util.Objects;
|
||||
@AllArgsConstructor
|
||||
public enum ManufacturerModelEnum {
|
||||
|
||||
enc001(ManufacturerEnum.SUNYARD, "enc001", "服务器密码机enc001"),
|
||||
enc001(ManufacturerEnum.SUNYARD, "SYD-001", "服务器密码机"),
|
||||
;
|
||||
|
||||
private final ManufacturerEnum manufacturer;
|
||||
|
@ -1,8 +1,13 @@
|
||||
package com.sunyard.chsm.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import com.sunyard.chsm.model.entity.Application;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
@ -10,4 +15,15 @@ import org.apache.ibatis.annotations.Mapper;
|
||||
*/
|
||||
@Mapper
|
||||
public interface ApplicationMapper extends BaseMapper<Application> {
|
||||
|
||||
|
||||
default Application selectByAppKey(String appKey) {
|
||||
List<Application> apps = selectList(new QueryWrapper<Application>().eq("app_key", appKey));
|
||||
if (CollectionUtils.isEmpty(apps)) {
|
||||
return null;
|
||||
}
|
||||
Assert.isTrue(apps.size() == 1, "app 数据异常");
|
||||
return apps.iterator().next();
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,7 +72,7 @@ public class R<T> {
|
||||
R<T> r = new R<>();
|
||||
r.setSuccess(false);
|
||||
r.setMessage(msg);
|
||||
r.setCode(500);
|
||||
r.setCode(400);
|
||||
return r;
|
||||
}
|
||||
|
||||
|
@ -21,16 +21,20 @@ public class Device {
|
||||
private Integer managePort;
|
||||
private String manufacturer;
|
||||
private String manufacturerModel;
|
||||
private Integer encKeyIdx;
|
||||
private String accessCredentials;
|
||||
|
||||
private Boolean connected;
|
||||
private LocalDateTime lastCheckTime;
|
||||
private LocalDateTime lastConnectedTime;
|
||||
|
||||
private Long groupId;
|
||||
private String groupName;
|
||||
private Integer weight;
|
||||
|
||||
private String tmkStatus;
|
||||
private String deviceSerial;
|
||||
private String pubKey;
|
||||
private String encTmk;
|
||||
private Boolean connected;
|
||||
private LocalDateTime lastCheckTime;
|
||||
private LocalDateTime lastConnectedTime;
|
||||
|
||||
private String remark;
|
||||
private LocalDateTime createTime;
|
||||
private LocalDateTime updateTime;
|
||||
|
@ -0,0 +1,46 @@
|
||||
package com.sunyard.chsm.utils;
|
||||
|
||||
import org.bouncycastle.util.encoders.Hex;
|
||||
|
||||
import java.util.Base64;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/6
|
||||
*/
|
||||
public abstract class CodecUtils {
|
||||
|
||||
public static String encodeBase64(byte[] data) {
|
||||
return Base64.getEncoder().encodeToString(data);
|
||||
}
|
||||
|
||||
public static byte[] decodeBase64(String str) {
|
||||
try {
|
||||
return Base64.getDecoder().decode(str);
|
||||
} catch (Exception var3) {
|
||||
if (str.length() > 32) {
|
||||
str = str.substring(0, 32) + "...";
|
||||
}
|
||||
|
||||
String format = String.format("参数[%s]不是正确的base64格式", str);
|
||||
throw new IllegalArgumentException(format);
|
||||
}
|
||||
}
|
||||
|
||||
public static String encodeHex(byte[] data) {
|
||||
return Hex.toHexString(data);
|
||||
}
|
||||
|
||||
public static byte[] decodeHex(String str) {
|
||||
try {
|
||||
return Hex.decode(str);
|
||||
} catch (Exception var3) {
|
||||
if (str.length() > 32) {
|
||||
str = str.substring(0, 32) + "...";
|
||||
}
|
||||
String format = String.format("参数[%s]不是正确的hex格式", str);
|
||||
throw new IllegalArgumentException(format);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -16,5 +16,13 @@
|
||||
<maven.compiler.target>8</maven.compiler.target>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>jakarta.validation</groupId>
|
||||
<artifactId>jakarta.validation-api</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
</project>
|
@ -0,0 +1,33 @@
|
||||
package com.sunyard.chsm.param;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
import javax.validation.constraints.Size;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/13
|
||||
*/
|
||||
@Data
|
||||
public class AppTokenReq {
|
||||
|
||||
/**
|
||||
* 平台分配的appKey
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(min = 16, max = 64, message = "appKey长度必须为16-64")
|
||||
private String appKey;
|
||||
/**
|
||||
* 时间戳毫秒数,与服务器时间不能超过5分钟
|
||||
*/
|
||||
@NotNull
|
||||
private Long random;
|
||||
/**
|
||||
* 使用appKey+random+appSecret作为原文,使用appSecret作为key,根据HmacSM3算法计算得到hmac值,转为Hex编码
|
||||
*/
|
||||
@NotBlank
|
||||
@Size(min = 32, max = 64, message = "hmac长度在60-64之间")
|
||||
private String hmac;
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package com.sunyard.chsm.param;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/11/13
|
||||
*/
|
||||
@Data
|
||||
public class AppTokenResp {
|
||||
/**
|
||||
* 获取的token的值
|
||||
*/
|
||||
private String token;
|
||||
}
|
@ -73,6 +73,7 @@ public abstract class DeviceDTO {
|
||||
* 管理端口
|
||||
*/
|
||||
private Integer managePort;
|
||||
private Integer encKeyIdx;
|
||||
/**
|
||||
* 访问凭证
|
||||
*/
|
||||
|
@ -2,7 +2,7 @@ package com.sunyard.config.security.jwt;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.sunyard.ssp.common.constant.SecurityConstant;
|
||||
import com.sunyard.chsm.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.modules.user.entity.ScUser;
|
||||
import com.sunyard.ssp.modules.user.service.IScUserService;
|
||||
import com.sunyard.ssp.utils.ResponseUtil;
|
||||
|
@ -3,7 +3,7 @@ package com.sunyard.config.security.jwt;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.sunyard.ssp.common.constant.SecurityConstant;
|
||||
import com.sunyard.chsm.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.utils.ResponseUtil;
|
||||
import com.sunyard.ssp.vo.TokenUser;
|
||||
import io.jsonwebtoken.Claims;
|
||||
|
@ -5,10 +5,10 @@ import cn.hutool.core.util.StrUtil;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
|
||||
import com.sunyard.chsm.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.common.PageVo;
|
||||
import com.sunyard.ssp.common.Result;
|
||||
import com.sunyard.ssp.common.constant.CommonConstant;
|
||||
import com.sunyard.ssp.common.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.common.enums.UserHeaderTypeEnum;
|
||||
import com.sunyard.ssp.modules.user.entity.ScDepartment;
|
||||
import com.sunyard.ssp.modules.user.entity.ScDepartmentHeader;
|
||||
|
@ -2,8 +2,8 @@ package com.sunyard.ssp.utils;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.google.gson.Gson;
|
||||
import com.sunyard.chsm.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.common.constant.CommonConstant;
|
||||
import com.sunyard.ssp.common.constant.SecurityConstant;
|
||||
import com.sunyard.ssp.modules.user.entity.ScPermission;
|
||||
import com.sunyard.ssp.modules.user.entity.ScRole;
|
||||
import com.sunyard.ssp.modules.user.entity.ScUser;
|
||||
|
@ -49,6 +49,13 @@
|
||||
<groupId>com.dm</groupId>
|
||||
<artifactId>DmJdbcDriver</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- JWT -->
|
||||
<dependency>
|
||||
<groupId>io.jsonwebtoken</groupId>
|
||||
<artifactId>jjwt</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -0,0 +1,111 @@
|
||||
package com.sunyard.chsm.auth;
|
||||
|
||||
|
||||
import com.sunyard.chsm.model.R;
|
||||
import com.sunyard.chsm.service.AppLoginService;
|
||||
import com.sunyard.chsm.utils.JsonUtils;
|
||||
import io.jsonwebtoken.ExpiredJwtException;
|
||||
import io.jsonwebtoken.JwtException;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @version V1.0
|
||||
* @since 2023/8/4
|
||||
*/
|
||||
@Slf4j
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class AppTokenFilter extends OncePerRequestFilter {
|
||||
|
||||
public static final Collection<String> WHITE_URL = Arrays.asList(
|
||||
"/appUser/getAppToken",
|
||||
"/appUser/getAppTokenTest"
|
||||
);
|
||||
|
||||
private final AppLoginService appLoginService;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
|
||||
String requestURI = request.getRequestURI();
|
||||
if (WHITE_URL.contains(requestURI)) {
|
||||
filterChain.doFilter(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
String tokenValue = extractToken(request);
|
||||
if (ObjectUtils.isEmpty(tokenValue)) {
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("请先获取token后再访问")));
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
AppUser user = appLoginService.verifyToken(tokenValue);
|
||||
request.setAttribute("APP_USER", user);
|
||||
filterChain.doFilter(request, response);
|
||||
} catch (ExpiredJwtException ex) {
|
||||
log.warn("token已过期: {}", requestURI);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("token已过期")));
|
||||
} catch (JwtException ex) {
|
||||
log.warn("token格式错误: {}", requestURI);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("token格式错误")));
|
||||
} catch (Exception ex) {
|
||||
log.error("未知异常: {}", requestURI, ex);
|
||||
response.setContentType(MediaType.APPLICATION_JSON_VALUE);
|
||||
response.getOutputStream().write(JsonUtils.toJsonBytes(R.error("发生异常")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
protected String extractToken(HttpServletRequest request) {
|
||||
// first check the header...
|
||||
String token = extractHeaderToken(request);
|
||||
|
||||
// bearer type allows a request parameter as well
|
||||
if (token == null) {
|
||||
logger.debug("Token not found in headers. Trying request parameters.");
|
||||
token = request.getParameter("access_token");
|
||||
if (token == null) {
|
||||
logger.debug("Token not found in request parameters. Not an OAuth2 request.");
|
||||
}
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
private static final String BEARER_TYPE = "Bearer";
|
||||
|
||||
private String extractHeaderToken(HttpServletRequest request) {
|
||||
Enumeration<String> headers = request.getHeaders("Authorization");
|
||||
while (headers.hasMoreElements()) { // typically there is only one (most servers enforce that)
|
||||
String value = headers.nextElement();
|
||||
if (value.toLowerCase().startsWith(BEARER_TYPE.toLowerCase())) {
|
||||
String authHeaderValue = value.substring(BEARER_TYPE.length()).trim();
|
||||
int commaIndex = authHeaderValue.indexOf(',');
|
||||
if (commaIndex > 0) {
|
||||
authHeaderValue = authHeaderValue.substring(0, commaIndex);
|
||||
}
|
||||
return authHeaderValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package com.sunyard.chsm.auth;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/6
|
||||
*/
|
||||
@Data
|
||||
public class AppUser {
|
||||
|
||||
private Long appId;
|
||||
private String name;
|
||||
private List<Long> serviceIds;
|
||||
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.sunyard.chsm.config;
|
||||
package com.sunyard.chsm.auth;
|
||||
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
|
@ -0,0 +1,19 @@
|
||||
package com.sunyard.chsm.auth;
|
||||
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/6
|
||||
*/
|
||||
public class UserContext {
|
||||
|
||||
|
||||
public static AppUser getCurrentUser() {
|
||||
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
|
||||
return (AppUser) requestAttributes.getAttribute("APP_USER", RequestAttributes.SCOPE_REQUEST);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
package com.sunyard.chsm.config;
|
||||
|
||||
import com.sunyard.chsm.model.R;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.validation.BindException;
|
||||
import org.springframework.validation.FieldError;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Arrays;
|
||||
import java.util.IllegalFormatException;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 全局controller异常处理
|
||||
*
|
||||
* @auther: ZS
|
||||
* @description:
|
||||
* @param:
|
||||
* @return:
|
||||
* @date: 2020/5/25 16:24
|
||||
*/
|
||||
@Slf4j
|
||||
@RestControllerAdvice
|
||||
public class GlobalExceptionResolver {
|
||||
|
||||
/**
|
||||
* 校验器
|
||||
*/
|
||||
@ExceptionHandler(BindException.class)
|
||||
@ResponseBody
|
||||
public R<?> handleBindException(BindException e) {
|
||||
log.info("校验器异常", e);
|
||||
FieldError fieldError = e.getBindingResult().getFieldError();
|
||||
return R.error(400, fieldError.getDefaultMessage());
|
||||
}
|
||||
|
||||
@ExceptionHandler(MethodArgumentNotValidException.class)
|
||||
public R<?> validExceptionHandler(MethodArgumentNotValidException ex) {
|
||||
return Optional.of(ex)
|
||||
.map(MethodArgumentNotValidException::getFieldError)
|
||||
.map(FieldError::getDefaultMessage)
|
||||
.map(message -> R.error(400, message))
|
||||
.get();
|
||||
}
|
||||
|
||||
private static final List<Class<? extends Exception>> EX_CLASS = Arrays.asList(
|
||||
IllegalArgumentException.class, IllegalStateException.class,
|
||||
IllegalFormatException.class,
|
||||
UnsupportedOperationException.class);
|
||||
|
||||
@ExceptionHandler(Exception.class)
|
||||
public R<?> exceptionHandler(Exception ex, HttpServletRequest request) {
|
||||
String errorMessage = buildErrorMessage(ex);
|
||||
for (Class<? extends Exception> eClass : EX_CLASS) {
|
||||
Exception exception = findException(eClass, ex);
|
||||
if (exception == null) {
|
||||
continue;
|
||||
}
|
||||
log.warn("Validation failed -> {} ", errorMessage);
|
||||
return R.error(400, exception.getMessage());
|
||||
}
|
||||
log.error("request: {} - {}, 系统异常 -> ", request.getMethod(), request.getRequestURI(), ex);
|
||||
return R.error("系统异常");
|
||||
}
|
||||
|
||||
public static <T extends Exception> T findException(Class<T> exClass, Throwable ex) {
|
||||
for (int i = 0; ex != null && i < 3; i++) {
|
||||
if (exClass.isAssignableFrom(ex.getClass())) {
|
||||
//noinspection unchecked
|
||||
return (T) ex;
|
||||
}
|
||||
ex = ex.getCause();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String buildErrorMessage(Throwable ex) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(ex.getMessage());
|
||||
StackTraceElement[] stackTrace = ex.getStackTrace();
|
||||
int i = 0;
|
||||
for (StackTraceElement stackTraceElement : stackTrace) {
|
||||
if (i++ >= 5) {
|
||||
break;
|
||||
}
|
||||
sb.append("\n\t").append(stackTraceElement.toString());
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
@ -1,17 +1,49 @@
|
||||
package com.sunyard.chsm.controller;
|
||||
|
||||
import com.sunyard.chsm.param.AppTokenReq;
|
||||
import com.sunyard.chsm.param.AppTokenResp;
|
||||
import com.sunyard.chsm.service.AppLoginService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 应用Token服务接口
|
||||
*
|
||||
* @author liulu
|
||||
* @version V1.0
|
||||
* @since 2023/8/4
|
||||
* @since 2024/12/4
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping
|
||||
public class AppLoginController {
|
||||
|
||||
@Resource
|
||||
private AppLoginService appLoginService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取应用Token接口
|
||||
* 密码服务平台为各个接入应用提供生成应用授权Token,
|
||||
* 接入应用需在密码服务平台获取了到平台分配的appKey和appSecret
|
||||
*
|
||||
* @param appTokenReq 请求参数
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/appUser/getAppToken")
|
||||
public AppTokenResp getAppToken(@Valid @RequestBody AppTokenReq appTokenReq) {
|
||||
return appLoginService.getAppToken(appTokenReq);
|
||||
}
|
||||
|
||||
@PostMapping("/appUser/getAppTokenTest")
|
||||
public AppTokenResp getAppTokenForTest(@Valid @RequestBody AppTokenReq appTokenReq) {
|
||||
return appLoginService.getAppTokenForTest(appTokenReq);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,39 @@
|
||||
package com.sunyard.chsm.controller;
|
||||
|
||||
import com.sunyard.chsm.model.R;
|
||||
import com.sunyard.chsm.model.dto.KeyInfoDTO;
|
||||
import com.sunyard.chsm.service.KeyInfoService;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 密钥管理类接口
|
||||
*
|
||||
* @author liulu
|
||||
* @since 2024/12/6
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/key/manage")
|
||||
public class KeyManageController {
|
||||
|
||||
@Resource
|
||||
private KeyInfoService keyInfoService;
|
||||
|
||||
/**
|
||||
* 启用密钥
|
||||
*
|
||||
* @param param 密钥id
|
||||
* @return id
|
||||
*/
|
||||
@PostMapping("/enable")
|
||||
public R<Void> enableKey(@Validated @RequestBody KeyInfoDTO.IDs param) {
|
||||
keyInfoService.enableKey(param.getIds());
|
||||
return R.ok();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,113 @@
|
||||
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.ApplicationMapper;
|
||||
import com.sunyard.chsm.model.entity.Application;
|
||||
import com.sunyard.chsm.param.AppTokenReq;
|
||||
import com.sunyard.chsm.param.AppTokenResp;
|
||||
import com.sunyard.chsm.utils.CodecUtils;
|
||||
import com.sunyard.chsm.utils.gm.BCSM3Utils;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import io.jsonwebtoken.Header;
|
||||
import io.jsonwebtoken.Jwts;
|
||||
import io.jsonwebtoken.SignatureAlgorithm;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.validation.Valid;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @author liulu
|
||||
* @since 2024/12/5
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class AppLoginService {
|
||||
|
||||
/**
|
||||
* token 过期时间, 分钟
|
||||
*/
|
||||
@Value("${chsm.token.expireTime:720}")
|
||||
private Integer tokenExpireTime;
|
||||
@Resource
|
||||
private ApplicationMapper applicationMapper;
|
||||
|
||||
public AppTokenResp getAppToken(AppTokenReq req) {
|
||||
Long random = req.getRandom();
|
||||
long now = System.currentTimeMillis();
|
||||
Assert.isTrue(now - random <= 5 * 60 * 1000, "请求已超时");
|
||||
String appKey = req.getAppKey();
|
||||
Application application = applicationMapper.selectByAppKey(appKey);
|
||||
Assert.isTrue(EnableStatus.ENABLED.getCode().equals(application.getStatus()), "此应用已停用");
|
||||
String data = appKey + random + application.getAppSecret();
|
||||
byte[] hmac = BCSM3Utils.hmac(application.getAppSecret().getBytes(), data.getBytes());
|
||||
String serverHmac = CodecUtils.encodeHex(hmac);
|
||||
if (!Objects.equals(req.getHmac(), serverHmac)) {
|
||||
log.warn("appKey: {}, req hmac: {}, server hmac: {}", appKey, req.getHmac(), serverHmac);
|
||||
throw new IllegalArgumentException("应用认证失败");
|
||||
}
|
||||
AppTokenResp resp = new AppTokenResp();
|
||||
resp.setToken(genToken(application));
|
||||
return resp;
|
||||
}
|
||||
|
||||
private String genToken(Application app) {
|
||||
Map<String, Object> claims = new HashMap<>();
|
||||
claims.put("appId", app.getId());
|
||||
claims.put("name", app.getName());
|
||||
claims.put("serviceIds", Collections.singletonList(app.getId()));
|
||||
Date now = new Date();
|
||||
return Jwts.builder()
|
||||
.setHeaderParam(Header.TYPE, Header.JWT_TYPE)
|
||||
.setClaims(claims)
|
||||
.setIssuedAt(now)
|
||||
.setExpiration(new Date(now.getTime() + tokenExpireTime * 60 * 1000))
|
||||
.setId(UUID.randomUUID().toString())
|
||||
.signWith(SignatureAlgorithm.HS512, SecurityConstant.JWT_SIGN_KEY)
|
||||
.compact();
|
||||
}
|
||||
|
||||
public AppTokenResp getAppTokenForTest(@Valid AppTokenReq req) {
|
||||
|
||||
// Long random = req.getRandom();
|
||||
// long now = System.currentTimeMillis();
|
||||
// Assert.isTrue(now - random <= 5 * 60 * 1000, "请求已超时");
|
||||
Application application = applicationMapper.selectByAppKey(req.getAppKey());
|
||||
Assert.isTrue(EnableStatus.ENABLED.getCode().equals(application.getStatus()), "此应用已停用");
|
||||
if (!Objects.equals(req.getHmac(), application.getAppSecret())) {
|
||||
log.warn("appKey: {}, req hmac: {},", req.getAppKey(), req.getHmac());
|
||||
throw new IllegalArgumentException("应用认证失败");
|
||||
}
|
||||
AppTokenResp resp = new AppTokenResp();
|
||||
resp.setToken(genToken(application));
|
||||
return resp;
|
||||
}
|
||||
|
||||
|
||||
public AppUser verifyToken(String token) {
|
||||
Claims claims = Jwts.parser()
|
||||
.setSigningKey(SecurityConstant.JWT_SIGN_KEY)
|
||||
.parseClaimsJws(token)
|
||||
.getBody();
|
||||
|
||||
AppUser user = new AppUser();
|
||||
user.setAppId(claims.get("appId", Long.class));
|
||||
user.setName(claims.get("name", String.class));
|
||||
user.setServiceIds(claims.get("serviceIds", List.class));
|
||||
return user;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -12,7 +12,7 @@ spring:
|
||||
# 数据源
|
||||
datasource:
|
||||
driverClassName: dm.jdbc.driver.DmDriver
|
||||
url: jdbc:dm://172.16.18.44:5236?schema=SSP&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=true&characterEncoding=UTF-8
|
||||
url: jdbc:dm://172.16.18.44:5236?schema=SUNYARD_SSP&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&useSSL=true&characterEncoding=UTF-8
|
||||
username: SUNYARD
|
||||
# Jasypt加密 可到common-utils中找到JasyptUtil加解密工具类生成加密结果 格式为ENC(加密结果)
|
||||
password: 123456
|
||||
|
@ -344,22 +344,26 @@ INSERT INTO SC_ROLE_PERMISSION (PERMISSION_ID, ROLE_ID) VALUES (189, 1);
|
||||
-- 密码设备
|
||||
CREATE TABLE sp_device (
|
||||
id BIGINT NOT NULL COMMENT 'id',
|
||||
name VARCHAR(255) COMMENT '名称',
|
||||
device_number VARCHAR(255) COMMENT '编号',
|
||||
manufacturer VARCHAR(255) COMMENT '制造厂商',
|
||||
manufacturer_model VARCHAR(255) COMMENT '制造厂商型号',
|
||||
service_ip VARCHAR(30) COMMENT '服务ip',
|
||||
name VARCHAR(255) DEFAULT '' COMMENT '名称',
|
||||
manufacturer VARCHAR(255) DEFAULT '' COMMENT '制造厂商',
|
||||
manufacturer_model VARCHAR(255) DEFAULT '' COMMENT '制造厂商型号',
|
||||
service_ip VARCHAR(30) DEFAULT '' COMMENT '服务ip',
|
||||
service_port INT COMMENT '服务端口',
|
||||
manage_ip VARCHAR(30) COMMENT '管理ip',
|
||||
manage_ip VARCHAR(30) DEFAULT '' COMMENT '管理ip',
|
||||
manage_port INT COMMENT '管理端口',
|
||||
access_credentials VARCHAR(1000) COMMENT '访问凭证',
|
||||
connected TINYINT NOT NULL DEFAULT 0,
|
||||
last_connected_time TIMESTAMP ,
|
||||
last_check_time TIMESTAMP ,
|
||||
enc_key_idx INT COMMENT '加密密钥索引',
|
||||
access_credentials VARCHAR(255) DEFAULT '' COMMENT '访问凭证',
|
||||
status VARCHAR(25) DEFAULT '' COMMENT '设备状态',
|
||||
group_id BIGINT NOT NULL DEFAULT 0 COMMENT '设备组id',
|
||||
group_name VARCHAR(255) NOT NULL DEFAULT '' COMMENT '设备组名称',
|
||||
weight INT DEFAULT 1 COMMENT '负载时权重',
|
||||
tmk_status VARCHAR(25) DEFAULT '' COMMENT 'tmk状态',
|
||||
device_serial VARCHAR(25) NOT NULL DEFAULT '' COMMENT '设备序列号',
|
||||
pub_key VARCHAR(400) NOT NULL DEFAULT '' COMMENT '设备公钥',
|
||||
enc_tmk VARCHAR(255) NOT NULL DEFAULT '' COMMENT 'tmk密文',
|
||||
connected TINYINT NOT NULL DEFAULT 0,
|
||||
last_connected_time TIMESTAMP ,
|
||||
last_check_time TIMESTAMP ,
|
||||
remark VARCHAR(500) NOT NULL DEFAULT '' COMMENT '备注',
|
||||
update_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||
create_time TIMESTAMP DEFAULT CURRENT_TIMESTAMP(),
|
||||
|
Loading…
Reference in New Issue
Block a user