Commit 7d08bfd6 authored by 赵啸非's avatar 赵啸非

修改构建api文档

parent 6f26d08c
...@@ -49,6 +49,12 @@ ...@@ -49,6 +49,12 @@
<artifactId>spring-data-redis</artifactId> <artifactId>spring-data-redis</artifactId>
</dependency> </dependency>
<!--Token生成与解析-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
</dependency>
<dependency> <dependency>
<groupId>com.github.shalousun</groupId> <groupId>com.github.shalousun</groupId>
<artifactId>smart-doc</artifactId> <artifactId>smart-doc</artifactId>
......
package com.mortals.xhx.base.framework.config;
import com.mortals.framework.springcloud.config.web.BaseWebMvcConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author: zxfei
* @date: 2021/8/13 0:24
* @description:
**/
@Configuration
public class AccountConfig {
@Bean
public BaseWebMvcConfigurer getBaseWebMvc(){
return new BaseWebMvcConfigurer(false,null);
}
}
...@@ -35,7 +35,7 @@ public class ExceptionHandle { ...@@ -35,7 +35,7 @@ public class ExceptionHandle {
ret.put(KEY_RESULT_MSG, ex.getMessage()); ret.put(KEY_RESULT_MSG, ex.getMessage());
} else { } else {
log.error("[system error]", e); log.error("[system error]", e);
ret.put(KEY_RESULT_MSG, "unknown exception!"); ret.put(KEY_RESULT_MSG, "未知错误!");
} }
return ret.toJSONString(); return ret.toJSONString();
} }
......
package com.mortals.xhx.base.framework.security;
import cn.hutool.core.util.IdUtil;
import com.mortals.framework.service.ICacheService;
import com.mortals.framework.util.StringUtils;
import com.mortals.xhx.base.system.user.model.UserEntity;
import com.mortals.xhx.common.key.Constant;
import io.jsonwebtoken.Claims;
import lombok.extern.apachecommons.CommonsLog;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
/**
* token验证处理
*
* @author zxfei
*/
@Component
@CommonsLog
public class AuthTokenService {
// 令牌自定义标识
@Value("${token.header}")
private String header;
// 令牌秘钥
@Value("${token.secret}")
private String secret;
// 令牌有效期(默认30分钟)
@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 ICacheService cacheService;
/**
* 获取信息
*
* @return 用户信息
*/
public UserEntity getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
String uuid = (String) claims.get(Constant.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
UserEntity userEntity = cacheService.get(userKey, UserEntity.class);
return userEntity;
} catch (Exception e) {
log.error("解析jwt token异常!", e);
return null;
}
}
return null;
}
/**
* 设置用户信息
*/
public void setUser(UserEntity user) {
if (StringUtils.isNotNull(user) && StringUtils.isNotEmpty(user.getToken())) {
refreshToken(user);
}
}
/**
* 删除用户身份信息
*/
public void delUser(String token) {
if (StringUtils.isNotEmpty(token)) {
String userKey = getTokenKey(token);
cacheService.del(userKey);
}
}
/**
* 创建令牌
*
* @param user 用户信息
* @return 令牌
*/
public String createToken(UserEntity user) {
String token = IdUtil.fastUUID();
user.setToken(token);
refreshToken(user);
Map<String, Object> claims = new HashMap<>();
claims.put(Constant.LOGIN_USER_KEY, token);
return createToken(claims);
}
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param user
* @return 令牌
*/
public void verifyToken(UserEntity user) {
long expireTime = user.getExpireTime();
long currentTime = System.currentTimeMillis();
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshToken(user);
}
}
/**
* 刷新令牌有效期
*
* @param user 信息
*/
public void refreshToken(UserEntity user) {
user.setLoginTime(System.currentTimeMillis());
user.setExpireTime(user.getLoginTime() + expireTime * MILLIS_MINUTE);
// 根据uuid将user缓存
String userKey = getTokenKey(user.getToken());
//设置有效时间 单位秒
cacheService.setnx(userKey, user, expireTime * MILLIS_MINUTE * MILLIS_SECOND);
}
/**
* 从数据声明生成令牌
*
* @param claims 数据声明
* @return 令牌
*/
private String createToken(Map<String, Object> claims) {
String token = Jwts.builder()
.setClaims(claims)
.signWith(SignatureAlgorithm.HS512, secret).compact();
return token;
}
/**
* 从令牌中获取数据声明
*
* @param token 令牌
* @return 数据声明
*/
private Claims parseToken(String token) {
return Jwts.parser()
.setSigningKey(secret)
.parseClaimsJws(token)
.getBody();
}
/**
* 从令牌中获取用户
*
* @param token 令牌
* @return 用户名
*/
public String getUserNumFromToken(String token) {
Claims claims = parseToken(token);
return claims.getSubject();
}
/**
* 获取请求token
*
* @param request
* @return token
*/
private String getToken(HttpServletRequest request) {
String token = request.getHeader(header);
if (StringUtils.isNotEmpty(token) && token.startsWith(Constant.TOKEN_PREFIX)) {
token = token.replace(Constant.TOKEN_PREFIX, "");
}
return token;
}
private String getTokenKey(String uuid) {
return Constant.LOGIN_TOKEN_KEY + uuid;
}
}
package com.mortals.xhx.base.framework.security;
import com.mortals.framework.common.HttpStatus;
import com.mortals.framework.exception.AppException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 安全服务工具类
*
* @author zxfei
*/
public class SecurityUtils {
/**
* 获取Authentication
*/
public static Authentication getAuthentication() {
return SecurityContextHolder.getContext().getAuthentication();
}
/**
* 生成BCryptPasswordEncoder密码
*
* @param password 密码
* @return 加密字符串
*/
public static String encryptPassword(String password) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.encode(password);
}
/**
* 判断密码是否相同
*
* @param rawPassword 真实密码
* @param encodedPassword 加密后字符
* @return 结果
*/
public static boolean matchesPassword(String rawPassword, String encodedPassword) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
return passwordEncoder.matches(rawPassword, encodedPassword);
}
/**
* 是否为管理员
*
* @param userId 用户ID
* @return 结果
*/
public static boolean isAdmin(Long userId) {
return userId != null && 1L == userId;
}
}
//package com.mortals.xhx.base.framework.security.filter;
//
//import com.alibaba.fastjson.JSONObject;
//import com.mortals.framework.util.StringUtils;
//import com.mortals.framework.web.interceptor.BaseInterceptor;
//import com.mortals.xhx.base.DeviceAuth;
//import com.mortals.xhx.busiz.security.SecurityUtils;
//import com.mortals.xhx.busiz.security.DeviceTokenService;
//import com.mortals.xhx.common.code.ApiRespCodeEnum;
//import com.mortals.xhx.module.device.model.DeviceEntity;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.stereotype.Component;
//import org.springframework.web.method.HandlerMethod;
//
//import javax.servlet.http.HttpServletRequest;
//import javax.servlet.http.HttpServletResponse;
//import java.lang.reflect.Method;
//
///**
// * 设备上报验证
// *
// * @author: zxfei
// * @date: 2022/4/11 15:50
// */
//@Component
//public class DeviceSubmitInterceptor extends BaseInterceptor {
//
// @Autowired
// private DeviceTokenService deviceTokenService;
//
// @Override
// public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// if (handler instanceof HandlerMethod) {
// HandlerMethod handlerMethod = (HandlerMethod) handler;
// Method method = handlerMethod.getMethod();
// DeviceAuth annotation = method.getAnnotation(DeviceAuth.class);
// if (annotation != null) {
// //校验
// if (this.verifyDevice(request)) {
// JSONObject ret = new JSONObject();
// ret.put("code", ApiRespCodeEnum.TOKEN_FAILED.getValue());
// ret.put("msg", ApiRespCodeEnum.TOKEN_FAILED.getLabel());
// super.writeJsonResponse(response, 200, JSONObject.toJSONString(ret));
// return false;
// }
// }
// return true;
// } else {
// return super.preHandle(request, response, handler);
// }
// }
//
// public boolean verifyDevice(HttpServletRequest request) {
// DeviceEntity device = deviceTokenService.getLoginDevice(request);
// if (StringUtils.isNotNull(device) && StringUtils.isNull(SecurityUtils.getAuthentication())) {
// deviceTokenService.verifyToken(device);
// return true;
// }
// return false;
//
// }
//
//
//}
...@@ -13,6 +13,7 @@ import com.mortals.framework.util.DateUtils; ...@@ -13,6 +13,7 @@ import com.mortals.framework.util.DateUtils;
import com.mortals.framework.util.HttpUtil; import com.mortals.framework.util.HttpUtil;
import com.mortals.framework.util.StringUtils; import com.mortals.framework.util.StringUtils;
import com.mortals.framework.web.BaseCRUDJsonController; import com.mortals.framework.web.BaseCRUDJsonController;
import com.mortals.xhx.base.framework.security.AuthTokenService;
import com.mortals.xhx.base.system.menu.model.MenuEntity; import com.mortals.xhx.base.system.menu.model.MenuEntity;
import com.mortals.xhx.base.system.menu.service.MenuService; import com.mortals.xhx.base.system.menu.service.MenuService;
import com.mortals.xhx.base.system.resource.service.ResourceService; import com.mortals.xhx.base.system.resource.service.ResourceService;
...@@ -49,6 +50,8 @@ public class LoginController extends BaseCRUDJsonController<UserService, UserFor ...@@ -49,6 +50,8 @@ public class LoginController extends BaseCRUDJsonController<UserService, UserFor
private ITokenService tokenService; private ITokenService tokenService;
@Autowired @Autowired
private ICacheService cacheService; private ICacheService cacheService;
@Autowired
private AuthTokenService authTokenService;
private static Log logger = LogFactory.getLog(LoginController.class); private static Log logger = LogFactory.getLog(LoginController.class);
...@@ -96,12 +99,14 @@ public class LoginController extends BaseCRUDJsonController<UserService, UserFor ...@@ -96,12 +99,14 @@ public class LoginController extends BaseCRUDJsonController<UserService, UserFor
data.put("id", userEntity.getId()); data.put("id", userEntity.getId());
data.put("userType", userEntity.getUserType()); data.put("userType", userEntity.getUserType());
String token = authTokenService.createToken(userEntity);
data.put("token", token);
//设置token 和过期时间 //设置token 和过期时间
// CookieInfo loginCookie = CookieService.getLoginCookie(request); // CookieInfo loginCookie = CookieService.getLoginCookie(request);
// if(!ObjectUtils.isEmpty(loginCookie)){ // if(!ObjectUtils.isEmpty(loginCookie)){
// //
// } // }
data.put("token", UUID.fastUUID().toString()); // data.put("token", UUID.fastUUID().toString());
data.put("expiresTime", DateUtils.addCurrDate(7).getTime()); data.put("expiresTime", DateUtils.addCurrDate(7).getTime());
// this.generateBlackCookie(request, response, loginName, urls); // this.generateBlackCookie(request, response, loginName, urls);
......
...@@ -10,6 +10,22 @@ import lombok.Data; ...@@ -10,6 +10,22 @@ import lombok.Data;
*/ */
@Data @Data
public class UserEntityExt extends BaseEntityLong { public class UserEntityExt extends BaseEntityLong {
/**
* 站点名称
*/
private String siteName; private String siteName;
/**
* 唯一标识
*/
private String token; private String token;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
} }
\ No newline at end of file
...@@ -27,17 +27,34 @@ public final class Constant { ...@@ -27,17 +27,34 @@ public final class Constant {
*/ */
public static final Integer SITE_CODE_NUM = 4; public static final Integer SITE_CODE_NUM = 4;
/**
* 验证码有效期(分钟)
*/
public static final Integer CAPTCHA_EXPIRATION = 2;
/**
* 登录设备 redis key
*/
public static final String LOGIN_TOKEN_KEY = "user:login:tokens:";
/**
* 令牌
*/
public static final String TOKEN = "token";
/**
* 令牌前缀
*/
public static final String TOKEN_PREFIX = "Bearer ";
/**
* 令牌前缀
*/
public static final String LOGIN_USER_KEY = "login_user_key";
/** 基础代码版本 Z-BASE.MANAGER-S1.0.0 */ /** 基础代码版本 Z-BASE.MANAGER-S1.0.0 */
public final static String BASEMANAGER_VERSION = "Z-BASE.MANAGER-S1.0.0"; public final static String BASEMANAGER_VERSION = "Z-BASE.MANAGER-S1.0.0";
public final static String Param_materialProperty = "materialProperty";
public final static String Param_materialType = "materialType";
public final static String Param_isMust = "isMust";
public final static String Param_electronicgs = "electronicgs";
public final static String Param_materialSource = "materialSource";
public final static String Param_paperGg = "paperGg";
public final static String Param_jianmMs = "jianmMs";
public final static String Param_sealWay = "sealWay";
public final static String Param_typeOptions = "typeOptions";
} }
...@@ -55,3 +55,11 @@ cookie: ...@@ -55,3 +55,11 @@ cookie:
port: 111 port: 111
upload: upload:
path: @profiles.filepath@ path: @profiles.filepath@
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcd1234
# 令牌有效期(默认60分钟)
expireTime: 60
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
<setting name="useGeneratedKeys" value="false" /> <setting name="useGeneratedKeys" value="false" />
<setting name="defaultExecutorType" value="REUSE" /> <setting name="defaultExecutorType" value="REUSE" />
<!-- 是否开始sql日志控制台打印 --> <!-- 是否开始sql日志控制台打印 -->
<!-- <setting name="logImpl" value="STDOUT_LOGGING" />--> <setting name="logImpl" value="STDOUT_LOGGING" />
</settings> </settings>
<plugins> <plugins>
<plugin interceptor="com.mortals.framework.thirty.mybatis.MortalsPagePlugin"> <plugin interceptor="com.mortals.framework.thirty.mybatis.MortalsPagePlugin">
......
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<configuration scan="true" scanPeriod="60 seconds" debug="false"> <configuration scan="true" scanPeriod="60 seconds" debug="false">
<!-- 定义变量后,可以使“${}”来使用变量 source来源为spring 上下文信息 -->
<springProperty scope="context" name="springApplicationName" source="spring.application.name"/> <springProperty scope="context" name="springApplicationName" source="spring.application.name"/>
<springProperty scope="context" name="serverPort" source="server.port"/> <springProperty scope="context" name="serverPort" source="server.port"/>
<springProperty scope="context" name="logFilePath" source="application.log.path" defaultValue="/mortals/app/logs" /> <springProperty scope="context" name="logFilePath" source="application.log.path" defaultValue="/mortals/app/logs" />
<springProperty scope="context" name="logLevel" source="application.log.level" defaultValue="INFO" /> <springProperty scope="context" name="logLevel" source="application.log.level" defaultValue="INFO" />
<property name="logFilePath" value="${logFilePath:-/mortals/app/logs}" />
<property name="logLevel" value="${logLevel:-INFO}" />
<!-- appender用来格式化日志输出节点,有俩个属性name和class,class用来指定哪种输出策略,常用就是控制台输出策略和文件输出策略 -->
<!-- 控制台输出策略-->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender"> <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder> <encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n</pattern> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n</pattern>
</encoder> </encoder>
</appender> </appender>
<!-- 文件输出策略-->
<appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="fileInfo" class="ch.qos.logback.core.rolling.RollingFileAppender">
<encoder> <encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n</pattern> <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level] [%thread] [%.50c\(%L\)] - %msg%n</pattern>
</encoder> </encoder>
<file>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log</file> <file>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!-- 文件保存策略-->
<fileNamePattern>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log.%d{yyyyMMdd}</fileNamePattern> <fileNamePattern>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-info.log.%d{yyyyMMdd}</fileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>15</MaxHistory>
</rollingPolicy> </rollingPolicy>
</appender> </appender>
<!-- 异常文件输出策略-->
<appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender"> <appender name="fileError" class="ch.qos.logback.core.rolling.RollingFileAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"> <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>ERROR</level> <level>ERROR</level>
...@@ -31,16 +38,24 @@ ...@@ -31,16 +38,24 @@
<file>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log</file> <file>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log</file>
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log.%d{yyyyMMdd}</fileNamePattern> <fileNamePattern>${logFilePath}/${springApplicationName:-default}/${serverPort:-default}-error.log.%d{yyyyMMdd}</fileNamePattern>
<!--日志文件保留天数-->
<MaxHistory>15</MaxHistory>
</rollingPolicy> </rollingPolicy>
</appender> </appender>
<logger name="com.mortals.xhx.module" level="DEBUG" additivity="false"/>
<root level="${logLevel}"> <root level="${logLevel}">
<appender-ref ref="console"/> <appender-ref ref="console"/>
<appender-ref ref="fileInfo"/> <appender-ref ref="fileInfo"/>
<appender-ref ref="fileError"/> <appender-ref ref="fileError"/>
</root> </root>
<!--TRACE < DEBUG < INFO < WARN < ERROR < FATAL -->
<!--用来设置某一个包或者具体的某一个类的日志打印级别、以及指定<appender>。<logger>仅有一个name属性,一个可选的level和一个可选的additivity属性。-->
<!-- name 用来指定受此loger约束的某一个包或者具体的某一个类-->
<!-- level 用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR, ALL 和 OFF,还有一个特俗值INHERITED或者同义词NULL,代表强制执行上级的级别。如果未设置此属性,那么当前logger将会继承上级的级别-->
<!-- additivity 是否向上级logger传递打印信息。默认是true。false:表示只用当前logger的appender-ref。true:表示当前logger的appender-ref和rootLogger的appender-ref都有效。-->
<logger name="com.mortals.xhx.module" level="INFO" additivity="false"> <logger name="com.mortals.xhx.module" level="INFO" additivity="false">
<appender-ref ref="console"/> <appender-ref ref="console"/>
<appender-ref ref="fileInfo"/> <appender-ref ref="fileInfo"/>
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment