...
 
Commits (73)
[V1.2.0] 2022.11.14
数据库:
1.新增hpgp_ks_hot表
2.hpgp_department_rank表新增rank_score = 0的全部医院数据
功能:
1.从公众号进入时,在李处理的一年内历史就诊记录的表中查询“公众号医院”的三个历史科室展示;
2.从“hpgp_ks_hot”表中查询展示“公众号医院”的科室(热门科室由医院提供,目前暂时用门诊量最大的三个科室代替)为了区分全区和公众号,新增了“gzh”字段;全区的“gzh”字段为“ALL”,公众号的“gzh”字段为“公众号医院编码”
3.在科室排名表(hpgp_department_rank_1028)中新增了全部医院/科室信息,其rank_score标为“0”,与全区排名科室做区分;按照standard_dept(=选择/机器人推荐的科室)、hospital_code(=公众号医院)、rank_score(=0)查询科室,选择有号的进行展示(一个医院中有多个同名科室,如果有号的超过3个那也只展示3个)
\ No newline at end of file
# hphy # hpgp
黄浦高血压精准导医 黄浦全科导医
\ No newline at end of file
package cn.sh.stc.sict.cloud.auth; package cn.sh.stc.sict.cloud.auth;
import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients; import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients;
import cn.sh.stc.sict.cloud.common.swagger.annotation.EnableSictSwagger2;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.SpringCloudApplication;
/** /**
* @author F_xh * @author F_xh
*/ */
@EnableSictSwagger2
@SpringCloudApplication @SpringCloudApplication
@EnableSictFeignClients @EnableSictFeignClients
public class SictAuthApplication { public class SictAuthApplication {
......
...@@ -51,6 +51,9 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter { ...@@ -51,6 +51,9 @@ public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {
.authorizeRequests() .authorizeRequests()
.antMatchers( .antMatchers(
"/token/**", "/token/**",
"/v2/api-docs",
"/webjars/**",
"/swagger-resources/**",
"/test/**", "/test/**",
"/actuator/**", "/actuator/**",
"/mobile/**").permitAll() "/mobile/**").permitAll()
......
package cn.sh.stc.sict.cloud.auth.endpoint; package cn.sh.stc.sict.cloud.auth.endpoint;
import cn.hutool.core.map.MapUtil; import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant; import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.PaginationConstants; import cn.sh.stc.sict.cloud.common.core.constant.PaginationConstants;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant; import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants; import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.security.annotation.Inner; import cn.sh.stc.sict.cloud.common.security.annotation.Inner;
import cn.sh.stc.sict.cloud.common.security.service.SictUser; import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.ConvertingCursor; import org.springframework.data.redis.core.ConvertingCursor;
import org.springframework.data.redis.core.Cursor; import org.springframework.data.redis.core.Cursor;
...@@ -26,6 +31,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore; ...@@ -26,6 +31,7 @@ import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
...@@ -35,6 +41,7 @@ import java.util.Map; ...@@ -35,6 +41,7 @@ import java.util.Map;
* @Author * @Author
* @Date * @Date
*/ */
@Slf4j
@RestController @RestController
@AllArgsConstructor @AllArgsConstructor
@RequestMapping("/token") @RequestMapping("/token")
...@@ -44,6 +51,7 @@ public class SictTokenEndpoint { ...@@ -44,6 +51,7 @@ public class SictTokenEndpoint {
private final TokenStore tokenStore; private final TokenStore tokenStore;
private final RedisTemplate redisTemplate; private final RedisTemplate redisTemplate;
private final CacheManager cacheManager; private final CacheManager cacheManager;
private final RemoteLogService remoteLogService;
/** /**
* 认证页面 * 认证页面
...@@ -61,7 +69,8 @@ public class SictTokenEndpoint { ...@@ -61,7 +69,8 @@ public class SictTokenEndpoint {
* @param authHeader Authorization * @param authHeader Authorization
*/ */
@DeleteMapping("/logout") @DeleteMapping("/logout")
public R logout(@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) { public R logout(HttpServletRequest request,
@RequestHeader(value = HttpHeaders.AUTHORIZATION, required = false) String authHeader) {
if (StrUtil.isBlank(authHeader)) { if (StrUtil.isBlank(authHeader)) {
return R.builder() return R.builder()
.code(Constant.BYTE_NO) .code(Constant.BYTE_NO)
...@@ -72,17 +81,27 @@ public class SictTokenEndpoint { ...@@ -72,17 +81,27 @@ public class SictTokenEndpoint {
String tokenValue = authHeader.replaceAll("(?i)Bearer", "").trim(); String tokenValue = authHeader.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue); OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) { if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return R.builder() return new R();
.code(Constant.BYTE_NO)
.data(Boolean.FALSE)
.msg("退出失败,token 无效").build();
} }
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken); OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
SictUser user = (SictUser) cacheManager.getCache(RedisCacheConstant.USER_DETAILS).get(auth2Authentication.getName()).get(); String username = auth2Authentication.getName();
SictUser user = (SictUser) cacheManager.getCache(RedisCacheConstant.USER_DETAILS).get(username).get();
cacheManager.getCache(RedisCacheConstant.USER_DETAILS) cacheManager.getCache(RedisCacheConstant.USER_DETAILS)
.evict(auth2Authentication.getName()); .evict(username);
tokenStore.removeAccessToken(accessToken); tokenStore.removeAccessToken(accessToken);
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "-用户登出");
sysLog.setParams(user.getName());
sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
// 保存退出的token
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
sysLog.setParams(token);
remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 退出成功, token:{} 已注销", username, token);
return new R<>(Boolean.TRUE); return new R<>(Boolean.TRUE);
} }
...@@ -100,6 +119,24 @@ public class SictTokenEndpoint { ...@@ -100,6 +119,24 @@ public class SictTokenEndpoint {
return new R<>(); return new R<>();
} }
/**
* 令牌管理调用
*
* @param token token
* @return
*/
@GetMapping("/check/{token}")
public R<Boolean> isValid(@PathVariable("token") String token) {
String tokenValue = token.replaceAll("(?i)Bearer", "").trim();
OAuth2AccessToken accessToken = tokenStore.readAccessToken(tokenValue);
if (accessToken == null || StrUtil.isBlank(accessToken.getValue())) {
return new R(false);
}
OAuth2Authentication auth2Authentication = tokenStore.readAuthentication(accessToken);
return new R<>(auth2Authentication.isAuthenticated());
}
/** /**
* 查询token * 查询token
......
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationFailureEvenHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationFailureEvenHandler extends AbstractAuthenticationFailureEvenHandler {
/**
* 处理登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
*/
@Override
public void handle(AuthenticationException authenticationException, Authentication authentication) {
log.info("用户:{} 登录失败,异常:{}", authentication.getPrincipal(), authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.concurrent.TimeUnit;
/**
*
* 登录操作次数锁定功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler {
private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
/**
* 密码错误超过 5 此自动锁定
* <p>
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
// 只处理账号密码错误异常
if (!(authenticationException instanceof BadCredentialsException) && userAccountProperties.getLimitFlag()) {
return;
}
String username = authentication.getName();
String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long times = redisTemplate.opsForValue().increment(key);
// 自动过期时间
redisTemplate.expire(key, userAccountProperties.getLimitTime(), TimeUnit.MINUTES);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationFailureLogEventHandler implements AuthenticationFailureHandler {
private final RemoteLogService logService;
/**
* 异步处理,登录失败方法
* <p>
*
* @param authenticationException 登录的authentication 对象
* @param authentication 登录的authenticationException 对象
* @param request 请求
* @param response 响应
*/
@Async
@Override
@SneakyThrows
public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
sysLog.setException(authenticationException.getLocalizedMessage());
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录失败,异常:{}", username, authenticationException.getLocalizedMessage());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpHeaders;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 退出事件处理
*
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationLogoutEventHandler implements AuthenticationLogoutHandler {
private final RemoteLogService logService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登出");
sysLog.setParams(username);
// 获取clientId 信息
OAuth2Authentication auth2Authentication = (OAuth2Authentication) authentication;
sysLog.setServiceId(auth2Authentication.getOAuth2Request().getClientId());
// 保存退出的token
String token = request.getHeader(HttpHeaders.AUTHORIZATION);
sysLog.setParams(token);
logService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 退出成功, token:{} 已注销", username, token);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AbstractAuthenticationSuccessEventHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
/**
* @Description
* @Author
* @Date
*/
@Slf4j
@Component
public class SictAuthenticationSuccessEventHandler extends AbstractAuthenticationSuccessEventHandler {
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
*/
@Override
public void handle(Authentication authentication) {
log.info("用户:{} 登录成功", authentication.getPrincipal());
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录操作次数锁定清楚功能
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLockEventHandler implements AuthenticationSuccessHandler {
private final RedisTemplate<String, String> redisTemplate;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
// String username = authentication.getName();
// String key = String.format("%s:%s:%s", CacheConstants.LOGIN_ERROR_TIMES, tenantKeyStrResolver.key(), username);
// redisTemplate.delete(key);
}
}
package cn.sh.stc.sict.cloud.auth.handler;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.util.SysLogUtils;
import cn.sh.stc.sict.cloud.upms.feign.RemoteLogService;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 登录成功日志记录
*/
@Slf4j
@Component
@AllArgsConstructor
public class SictAuthenticationSuccessLogEventHandler implements AuthenticationSuccessHandler {
private final RemoteLogService remoteLogService;
/**
* 处理登录成功方法
* <p>
* 获取到登录的authentication 对象
*
* @param authentication 登录对象
* @param request 请求
* @param response 返回
*/
@Async
@Override
public void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response) {
String username = authentication.getName();
SysLog sysLog = SysLogUtils.getSysLog(request, username);
sysLog.setTitle(username + "用户登录");
sysLog.setParams(username);
remoteLogService.saveLog(sysLog, SecurityConstants.FROM_IN);
log.info("用户:{} 登录成功", username);
}
}
...@@ -11,10 +11,8 @@ spring: ...@@ -11,10 +11,8 @@ spring:
nacos: nacos:
server-addr: 127.0.0.1:8848 server-addr: 127.0.0.1:8848
discovery: discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config: config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
\ No newline at end of file
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
server:
port: 12254
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
shared-configs:
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
<appender-ref ref="error"/> <appender-ref ref="error"/>
</logger> </logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 --> <!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="DEBUG"> <root level="ERROR">
<appender-ref ref="console"/> <appender-ref ref="console"/>
<appender-ref ref="debug"/> <appender-ref ref="debug"/>
</root> </root>
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
<mysql.connector.version>8.0.15</mysql.connector.version> <mysql.connector.version>8.0.15</mysql.connector.version>
<swagger.core.version>1.5.22</swagger.core.version> <swagger.core.version>1.5.22</swagger.core.version>
<swagger.version>2.9.2</swagger.version> <swagger.version>2.9.2</swagger.version>
<hutool.version>5.5.1</hutool.version> <hutool.version>5.7.0</hutool.version>
<poi.version>4.1.0</poi.version> <poi.version>4.1.0</poi.version>
<pinyin4j.version>2.5.1</pinyin4j.version> <pinyin4j.version>2.5.1</pinyin4j.version>
<ttl.version>2.10.1</ttl.version> <ttl.version>2.10.1</ttl.version>
...@@ -58,11 +58,11 @@ ...@@ -58,11 +58,11 @@
<artifactId>cloud-common-core</artifactId> <artifactId>cloud-common-core</artifactId>
<version>${sict.version}</version> <version>${sict.version}</version>
</dependency> </dependency>
<dependency> <!-- <dependency>-->
<groupId>cn.sh.stc.sict</groupId> <!-- <groupId>cn.sh.stc.sict</groupId>-->
<artifactId>cloud-auth-api</artifactId> <!-- <artifactId>cloud-auth-api</artifactId>-->
<version>${sict.version}</version> <!-- <version>${sict.version}</version>-->
</dependency> <!-- </dependency>-->
<dependency> <dependency>
<groupId>cn.sh.stc.sict</groupId> <groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-dynamic-gateway</artifactId> <artifactId>cloud-common-dynamic-gateway</artifactId>
......
...@@ -80,5 +80,13 @@ ...@@ -80,5 +80,13 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId> <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency> </dependency>
<!--纳里平台接口调用SDK(公众号用户信息接口)-->
<dependency>
<groupId>com.ngarihealth</groupId>
<artifactId>openapi-sdk-java</artifactId>
<version>1.0-RELEASE</version>
<scope>system</scope>
<systemPath>${project.basedir}/libs/openapi-sdk-java-1.0-RELEASE.jar</systemPath>
</dependency>
</dependencies> </dependencies>
</project> </project>
\ No newline at end of file
...@@ -10,73 +10,33 @@ public class RedisCacheConstant { ...@@ -10,73 +10,33 @@ public class RedisCacheConstant {
/** /**
* 用户角色与终端类型的分隔符 * 用户角色与终端类型的分隔符
*/ */
public static final String USER_ROLE_SEPARATOR = "@"; public static final String APP = "hpgp:";
/**
* 微信用户信息明细
*/
public static final String WX_USER_DETAILS = "wx_user_details";
/**
* 基础用户信息明细 base
*/
public static final String BASE_USER_DETAILS = "base_user_details";
/**
* 基础学生信息
*/
public static final String CURRENT_STUDENT = "current_student";
/** /**
* 基础用户信息明细 * 基础用户信息明细
*/ */
public static final String USER_DETAILS = "user_details"; public static final String USER_DETAILS = APP + "user_details";
/** /**
* 当前登录用户的角色信息 * 当前登录用户的角色信息
*/ */
public static final String TOKEN_ROLES = "token_roles"; public static final String TOKEN_ROLES = APP + "token_roles";
/** /**
* 当前登录用户的详细信息 * 当前登录用户的详细信息
*/ */
public static final String TOKEN_CURRENT = "token_current"; public static final String TOKEN_CURRENT = APP + "token_current";
/**
* 微信应用缓存
*/
public static final String WECHAT_OFFICALS = "wechat_officals";
/**
* 冷知识点赞数量
*/
public static final String CLD_TRIVIA_NUM = "cld_trivia_num";
/**
* 积分
*/
public static final String CREDIT = "credit";
public static final String CREDIT_NEXT_LEVEL_BY_SCORE = "credit:score:next";
public static final String CREDIT_LEVEL_BY_SCORE = "credit:score:current";
/** /**
* 未付款订单 * /**
* 用户短信验证码
*/ */
public static final String PAY_ORDER_NOT_PAID = "order_info:not_paid"; public static final String SICT_PHONE_CODE_KEY = APP + "SICT_PHONE_CODE_KEY";
/** /**
* temp 微信支付开关 * 路由存放
*/ */
public static final String WECHAT_APPLE_PAY_SWITCH = "order_info:wechat_apple_pay_switch"; public static final String ROUTE_KEY = APP + "hp_gateway_route_key";
/**
* 是否需要弹窗
*/
public static final String WECHAT_POP_UP = "pop-up:kindergarten";
public static final String DEPT_NUM_SOURCE_RESULT = "dept_num_source_result";
/** public static final String DEFAULT_CODE_KEY = APP + "SICT_DEFAULT_CODE_KEY_";
* 用户短信验证码
*/
public static final String SICT_PHONE_CODE_KEY = "SICT_PHONE_CODE_KEY";
/**
* 路由存放
*/
public static final String ROUTE_KEY = "hp_gateway_route_key";
/** public static final String LOGIN_ERROR_TIMES = APP + "login_error_times";
* 验证码前缀
*/
public static final String DEFAULT_CODE_KEY = "SICT_DEFAULT_CODE_KEY_";
} }
...@@ -136,6 +136,14 @@ public interface SecurityConstants { ...@@ -136,6 +136,14 @@ public interface SecurityConstants {
* openid * openid
*/ */
String DETAILS_APPID = "appid"; String DETAILS_APPID = "appid";
/**
* 医院代码
*/
String HOSPITAL_CODE = "hospitalCode";
/**
* 香山中医用户信息
*/
String XSZY_USER_INFO = "xszyUserInfo";
/** /**
* 租户ID 字段 * 租户ID 字段
*/ */
......
...@@ -11,4 +11,6 @@ public interface ServiceNameConstants { ...@@ -11,4 +11,6 @@ public interface ServiceNameConstants {
* 认证中心 * 认证中心
*/ */
String UPMS_SERVICE = "cloud-upms-biz"; String UPMS_SERVICE = "cloud-upms-biz";
String AUTH_SERVICE = "cloud-auth";
} }
package cn.sh.stc.sict.cloud.common.core.constant;
public class UserConstant {
public final static String USER_SOURCE_MOBILE = "mobile";
public final static String USER_SOURCE_SSB = "wd_ssb";
/**
* 0:社保卡
* 1:医保卡
* 2:统一自费就诊卡
* 9:其他卡
*/
public final static String SOCIAL_SECURITY_CARD = "0";
public final static String MEDICAL_INSURANCE_CARD = "1";
public final static String UNIFIED_MEDICAL_TREATMENT_EXPENSE_CARD = "2";
public final static String OTHER_CARD = "9";
}
...@@ -12,6 +12,7 @@ import lombok.Getter; ...@@ -12,6 +12,7 @@ import lombok.Getter;
@AllArgsConstructor @AllArgsConstructor
public enum BizCodeConstant { public enum BizCodeConstant {
/* */ /* */
USER_PWD_LIMIT(99,""),
TEMP(0,""); TEMP(0,"");
private Integer code; private Integer code;
......
...@@ -22,6 +22,31 @@ public enum LoginTypeEnum { ...@@ -22,6 +22,31 @@ public enum LoginTypeEnum {
*/ */
SMS("sms", "验证码登录"), SMS("sms", "验证码登录"),
/**
* 验证码登录
*/
SSB("ssb", "随申办token"),
/**
* 纳里用户系统公众号
* 香山中医医院公众号
* 上海市黄浦区精神卫生中心
* 上海市黄浦区妇幼保健所
* 上海市黄浦区顺昌医院
* 上海市黄浦区半淞园路街道社区卫生服务中心
*/
WOA_NL("woa_nl", "纳里用户系统公众号登录"),
/**
* 打浦桥,外滩,小东门,老西门,豫园,五里桥,淮海,瑞二
*/
WOA_ZZ("woa_zz", "中智用户系统公众号登录"),
/**
* 上海交通大学医学院附属第九人民医院黄浦分院
*/
WOA_WD("woa_wd", "万达公众号用户系统公众号登录"),
WOA_ND("woa_nd", "万达公众号用户系统南东社区公众号登录"),
/** /**
* H5登录 * H5登录
*/ */
...@@ -46,4 +71,13 @@ public enum LoginTypeEnum { ...@@ -46,4 +71,13 @@ public enum LoginTypeEnum {
* 描述 * 描述
*/ */
private final String description; private final String description;
public static LoginTypeEnum match(String type) {
for (LoginTypeEnum loginType : LoginTypeEnum.values()) {
if (loginType.getType().equals(type)) {
return loginType;
}
}
return null;
}
} }
package cn.sh.stc.sict.cloud.common.core.constant.enums;
import lombok.AllArgsConstructor;
import lombok.Getter;
import java.util.Arrays;
/**
* 中智用户体系枚举
*
* @author gao
* @date 2023/04/27 15:16
*/
@AllArgsConstructor
@Getter
public enum ZzUserApiEnum {
/**
* 中智用户体系公众号信息
*/
DAPUQIAO("/dpq", "wxd831bfb5879b3522", "booking.hpdapuqiao.com", "42502942300"),
WAITAN("/wt", "wx8f9db9da2fbe1d5b", "booking.hpwaitan.com", "42503639100"),
WULIQIAO("/wlq", "wxa29d485b25f6aaf0", "gzh.hpwlq.com", "79705627000"),
HUAIHAIZHONGLU("/hhzl", "wxf2cbbfdc28aa93e6", "gzh.hphuaihai.com", "42502940700"),
RUIJINERLU("/rjel", "wxf0b1f6ee9e16effd", "booking.shruier.cn", "42502992500"),
YUYUAN("/yy", "wx3691d4535427bfc5", "gzh.yuyuanswydt.cn", "42502884200"),
XIAODONGMEN("/xdm", "wx1e4ca6fecfa4a0bb", "gzh.hpxiaodongmen.com", "42507025800"),
LAOXIMEN("/lxm", "wxdf6e240a731c70ea", "booking.hplxmsw.cn", "42507018600");
private final String relativePath;
private final String appid;
private final String domain;
private final String institutionCode;
public static ZzUserApiEnum find(String appid) {
return Arrays.stream(values())
.filter(institution -> institution.appid.equals(appid))
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No Institution with appid " + appid));
}
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
/**
* 万达随申办接口用户绑卡信息
*/
@Data
public class WDUserCardInfo {
private String id;
private String cardNo;
private String cardType;
private String hospitalId;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 万达随申办接口用户信息
*/
@Data
public class WDUserInfo {
private String token;
private String id;
private String username;
private String name;
private String personcard;
private String mobile;
private Date birth;
private String avatar;
private Byte gender;
private String verifyStatus;
private Date regtime;
private String openid;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
import java.util.List;
/**
* 万达公众号-用户基础信息
*
* @author gao
* @date 2023/01/13 09:39
*/
@Data
public class WOAWDUserInfo {
private String id;
private String username;
private String personcard;
private String mobile;
private String avator;
private Byte gender;
private Integer verifyStatus;
private Date regtime;
private String openid;
private List<Card> cards;
@Data
public static class Card {
private String hospitalId;
private String cardType;
private String cardNo;
}
}
package cn.sh.stc.sict.cloud.common.core.dto;
import lombok.Data;
import java.util.Date;
/**
* 中智公众号-用户基础信息
*
* @author gao
* @date 2023/01/13 09:39
*/
@Data
public class WOAZzUserInfo {
private String id;
private String username;
private String personcard;
private String mobile;
private String avator;
private Byte gender;
private Integer verifyStatus;
private Date regtime;
private String openid;
}
package cn.sh.stc.sict.cloud.common.core.dto;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.UserConstant;
import lombok.Data;
/**
* 公众号-香山中医医院用户信息
*/
@Data
public class XSZYUserInfo {
/**
* 用户ID
*/
private String userId;
/**
* 就诊人ID
*/
private String mpiId;
/**
* 姓名
*/
private String patientName;
/**
* 证件号
*/
private String certificate;
/**
* 证件类型
*/
private String certificateType;
/**
* 手机号
*/
private String mobile;
/**
* 医院编码
*/
private String hospitalCode;
/**
* 卡类型0:社保卡;1:医保卡;2:统一自费就诊卡;9:其他卡
*/
private String mediCardType;
/**
* 卡号
*/
private String mediCardId;
/**
* 将纳里用户卡类型映射为挂号时的卡类型
* 1:就诊卡
* 2:医保卡
* 3:病历号
* 4:健康卡
* 5:社保卡
* 6:住院卡
* 7:院内健健康卡
* 8:体检卡
*/
public static String fromNlType(String mediCardType) {
if (StrUtil.isBlank(mediCardType)) {
return null;
}
if (mediCardType.equals("5")) {
return UserConstant.SOCIAL_SECURITY_CARD;
} else if (mediCardType.equals("2")) {
return UserConstant.MEDICAL_INSURANCE_CARD;
} else if (mediCardType.equals("1")) {
return UserConstant.UNIFIED_MEDICAL_TREATMENT_EXPENSE_CARD;
} else {
return UserConstant.OTHER_CARD;
}
}
}
...@@ -292,6 +292,11 @@ public class CryptUtil { ...@@ -292,6 +292,11 @@ public class CryptUtil {
String pwdjm = toAES(pwd, token); String pwdjm = toAES(pwd, token);
System.out.println(toAES(name, token)); System.out.println(toAES(name, token));
System.out.println(pwdjm); System.out.println(pwdjm);
String text = "FaU+wh88VZr4E+YufJyuJMnxPJlQtyst/BkgZ0chipVSTcKNXVEGj9AhQ99wPGzC3QeNAYTU0slgpjqPCEX9lg==";
String test = "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";
System.out.println(AESToString(test,token));
// String pwdorigin = AESToString(pwdjm, token); // String pwdorigin = AESToString(pwdjm, token);
// System.out.println(pwdorigin); // System.out.println(pwdorigin);
......
package cn.sh.stc.sict.cloud.common.core.util; package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
...@@ -118,4 +119,7 @@ public class NumberUtil { ...@@ -118,4 +119,7 @@ public class NumberUtil {
} }
public static Long getLongValue(String value) {
return StrUtil.isBlank(value) ? 0L : Long.parseLong(value);
}
} }
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserCardInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WDUserInfo;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import java.util.List;
/**
* 随申办工具类
*/
@Slf4j
@UtilityClass
public class SsbUtil {
// 外网测试地址 https://ffyjs.hpwjsns.org.cn:9071/
// private final static String USER_URL = "https://ffyjs.hpwjsns.org.cn:9071/fdapp/api/account/v1/token/info";
// private final static String CARD_URL = "https://ffyjs.hpwjsns.org.cn:9071/fdapp/api/account/v1/user/cards";
// 内网线上地址 http://173.18.1.97:9071/fdapp/
private final static String USER_URL = "http://173.18.1.97:9071/fdapp/api/account/v1/token/info";
private final static String CARD_URL = "http://173.18.1.97:9071/fdapp/api/account/v1/user/cards";
/**
* 获取用户信息
*
* @param token
* @return
*/
public WDUserInfo getUserInfo(String token) {
try {
HttpResponse response = HttpRequest.get(USER_URL)
.header("backdoor", "1")
.header("access-token", token)
.execute();
if (response.getStatus() != 200) {
log.error("随申办token获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WDUserInfo.class);
} catch (Exception ex) {
log.error("随申办token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 获取用户绑卡信息
*
* @param token
* @return
*/
public List<WDUserCardInfo> getUserCardInfoList(String token) {
try {
HttpResponse response = HttpRequest.get(CARD_URL)
.header("backdoor", "1")
.header("access-token", token)
.execute();
if (response.getStatus() != 200) {
log.error("随申办token获取绑卡信息异常-1");
return null;
}
return JSONUtil.toList(JSONUtil.parseArray(response.body()), WDUserCardInfo.class);
} catch (Exception ex) {
log.error("随申办token获取绑卡信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
}
...@@ -41,6 +41,7 @@ import java.util.*; ...@@ -41,6 +41,7 @@ import java.util.*;
public class WebUtils extends org.springframework.web.util.WebUtils { public class WebUtils extends org.springframework.web.util.WebUtils {
private final String BASIC_ = "Basic "; private final String BASIC_ = "Basic ";
private final String UNKNOWN = "unknown"; private final String UNKNOWN = "unknown";
private final String LOCAL127 = "127.0.0.1";
/** /**
* 判断是否ajax请求 * 判断是否ajax请求
...@@ -158,7 +159,7 @@ public class WebUtils extends org.springframework.web.util.WebUtils { ...@@ -158,7 +159,7 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
return getIP(WebUtils.getRequest()); return getIP(WebUtils.getRequest());
} }
public String getSession(){ public String getSession() {
return WebUtils.getSessionId(WebUtils.getRequest()); return WebUtils.getSessionId(WebUtils.getRequest());
} }
...@@ -193,6 +194,41 @@ public class WebUtils extends org.springframework.web.util.WebUtils { ...@@ -193,6 +194,41 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
return StringUtils.isBlank(ip) ? null : ip.split(",")[0]; return StringUtils.isBlank(ip) ? null : ip.split(",")[0];
} }
public String getIP(ServerHttpRequest request) {
HttpHeaders headers = request.getHeaders();
String ip = headers.getFirst("x-forwarded-for");
if (StrUtil.isNotBlank(ip) && !UNKNOWN.equalsIgnoreCase(ip)) {
// 多次反向代理后会有多个ip值,第一个ip才是真实ip
if (ip.indexOf(",") != -1) {
if (LOCAL127.equals(ip.split(",")[0])) {
ip = ip.split(",")[1];
} else {
ip = ip.split(",")[0];
}
}
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("Proxy-Client-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("WL-Proxy-Client-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_CLIENT_IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = headers.getFirst("X-Real-IP");
}
if (StrUtil.isBlank(ip) || UNKNOWN.equalsIgnoreCase(ip)) {
ip = request.getRemoteAddress().getAddress().getHostAddress();
}
return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
}
/** /**
* 从request 获取CLIENT_ID * 从request 获取CLIENT_ID
* *
...@@ -225,13 +261,12 @@ public class WebUtils extends org.springframework.web.util.WebUtils { ...@@ -225,13 +261,12 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
} }
/** /**
*
* @param request HttpServletRequest * @param request HttpServletRequest
* tip: 不可使用WebUtils.getRequest()获取 * tip: 不可使用WebUtils.getRequest()获取
* @param allowSuffix 文件后缀名 多个以","逗号分隔 * @param allowSuffix 文件后缀名 多个以","逗号分隔
* @return * @return
*/ */
public MultipartFile getRequestFile(@NonNull HttpServletRequest request, @NonNull String allowSuffix){ public MultipartFile getRequestFile(@NonNull HttpServletRequest request, @NonNull String allowSuffix) {
String errorMsg = StrUtil.EMPTY; String errorMsg = StrUtil.EMPTY;
String[] suffixs = allowSuffix.split(","); String[] suffixs = allowSuffix.split(",");
...@@ -243,26 +278,27 @@ public class WebUtils extends org.springframework.web.util.WebUtils { ...@@ -243,26 +278,27 @@ public class WebUtils extends org.springframework.web.util.WebUtils {
file = fileEntity.getValue(); file = fileEntity.getValue();
String originalFilename = file.getOriginalFilename(); String originalFilename = file.getOriginalFilename();
String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1); String suffix = originalFilename.substring(originalFilename.lastIndexOf('.') + 1);
if(suffixSet.contains(suffix)){ if (suffixSet.contains(suffix)) {
break; break;
} }
errorMsg = "文件类型不支持"; errorMsg = "文件类型不支持";
} }
Assert.isTrue(StrUtil.isBlank(errorMsg), errorMsg); Assert.isTrue(StrUtil.isBlank(errorMsg), errorMsg);
Objects.requireNonNull(file,"excel导入 ---------->>>>>>> 未检测到上传文件"); Objects.requireNonNull(file, "excel导入 ---------->>>>>>> 未检测到上传文件");
return file; return file;
} }
/** /**
* 导出excel * 导出excel
*
* @param list 数据 * @param list 数据
* @param writer * @param writer
* @param name 文件名 * @param name 文件名
*/ */
@SneakyThrows @SneakyThrows
public void exportExcel(@NonNull List list,@NonNull ExcelWriter writer, String name) { public void exportExcel(@NonNull List list, @NonNull ExcelWriter writer, String name) {
writer.setOnlyAlias(true); writer.setOnlyAlias(true);
HttpServletResponse response = WebUtils.getResponse(); HttpServletResponse response = WebUtils.getResponse();
//response为HttpServletResponse对象 //response为HttpServletResponse对象
......
package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.constant.enums.ZzUserApiEnum;
import cn.sh.stc.sict.cloud.common.core.dto.WOAWDUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.WOAZzUserInfo;
import cn.sh.stc.sict.cloud.common.core.dto.XSZYUserInfo;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import ngari.openapi.Client;
import ngari.openapi.JSONResponseBean;
import ngari.openapi.Request;
import ngari.openapi.Response;
/**
* 医院公众号工具类
* <p>
* 注意事项:
* 1.医院编码是否传递
* 2.手机号必须有,作为用户身份的唯一标识
*/
@Slf4j
@UtilityClass
public class WoaUtil {
/**
* 香山中医医院公众号用户信息获取接口地址(纳里)
*/
private final static String WOA_XSZY_URL = "https://openapi.ngarihealth.com";
private final static String WOA_XSZY_GATEWAY_URL = "/openapi/gateway";
/**
* 内网代理请求地址
*/
private final static String WOA_XSZY_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/xszy";
/**
* 获取用户信息请求地址
*/
private final static String WOA_XSZY_USER_INFO_API_URL = WOA_XSZY_PROXY_PASS_URL + WOA_XSZY_GATEWAY_URL;
/**
* 接口授权信息
*/
private final static String APP_KEY = "ngari635f7f4b0e980e63";
private final static String APP_SECRET = "0e980e634196fcde";
/**
* 获取用户信息服务ID
*/
private final static String SERVICE_ID = "openapi.authenticationService";
/**
* 获取用户信息方法
*/
private final static String METHOD = "apiGetUserInfo";
/**
* 响应头请求唯一ID
*/
private final static String RESPONSE_HEADER_REQUEST_ID = "X-Ca-RequestId";
/**
* 获取用户信息
*
* @param ngCode 纳里授权码
* @return
*/
public XSZYUserInfo getXszyUserInfo(String ngCode) {
//如果开启加密,则必填
String encodingAesKey = "";
Client client = new Client(WOA_XSZY_USER_INFO_API_URL, APP_KEY, APP_SECRET, encodingAesKey);
try {
// 入参说明[授权码,是否回调,拓展参数]
Request request = new Request(SERVICE_ID, METHOD, ListUtil.toList(ngCode, false, null));
Response response = client.execute(request);
if (response.isSuccess()) {
JSONResponseBean result = response.getJsonResponseBean();
XSZYUserInfo xszyUserInfo = Convert.convert(XSZYUserInfo.class, result.getBody());
return xszyUserInfo;
} else {
log.error("香山中医医院公众号token获取用户信息异常-1,requestId = [{}],caError = [{}],error = [{}]", response.getHeader(RESPONSE_HEADER_REQUEST_ID), response.getCaErrorMsg(), response.getErrorMessage());
log.error(JSONUtil.toJsonStr(response));
return null;
}
} catch (Exception ex) {
log.error("香山中医医院公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 中智公众号用户url
* 打浦桥,外滩,小东门,老西门,豫园,五里桥,淮海,瑞二
*/
private final static String WOA_ZZ_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/zz";
// private final static String WOA_ZZ_PROXY_PASS_URL = "https://booking.hpdapuqiao.com";
private final static String ZZ_USER_INFO_API_URL = "/api/Other/GetPerson";
//private final static String WOA_WD_PROXY_PASS_URL = "https://wxgzh.shjyhpfy.com/api/hosservice/visit/GetUserInfoByToken";
private final static String WOA_WD_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/wd";
private final static String WOA_WD_USER_INFO_URL = WOA_WD_PROXY_PASS_URL + "/api/hosservice/visit/GetUserInfoByToken";
private final static String WOA_WD_ND_PROXY_PASS_URL = "http://30.30.5.74:9988/woa/wdnd";
/**
* 南东社区公众号用户信息
*/
private final static String WOA_WD_ND_USER_INFO_URL = WOA_WD_ND_PROXY_PASS_URL + "/gzh/user/token/info";
public WOAZzUserInfo getZzUserInfo(String appid, String accessToken) {
try {
ZzUserApiEnum zzUserApiEnum = ZzUserApiEnum.find(appid);
String url = WOA_ZZ_PROXY_PASS_URL + zzUserApiEnum.getRelativePath() + ZZ_USER_INFO_API_URL;
HttpResponse response = HttpRequest.get(url)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("中智获取用户信息异常-1");
return null;
}
log.error("response = {}", JSONUtil.toJsonStr(response.body()));
return JSONUtil.toBean(response.body(), WOAZzUserInfo.class);
} catch (Exception ex) {
log.error("中智token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
public WOAWDUserInfo getWoaWDUserInfo(String accessToken) {
try {
HttpResponse response = HttpRequest.get(WOA_WD_USER_INFO_URL)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("万达公众号获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WOAWDUserInfo.class);
} catch (Exception ex) {
log.error("万达公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
/**
* 获取万达南东社区公众号用户信息
* @param accessToken
* @return
*/
public WOAWDUserInfo getThirdPartyUserInfo(String accessToken){
try {
HttpResponse response = HttpRequest.get(WOA_WD_ND_USER_INFO_URL)
.header("access-token", accessToken)
.execute();
if (response.getStatus() != 200) {
log.error("万达公众号获取用户信息异常-1");
return null;
}
return JSONUtil.toBean(response.body(), WOAWDUserInfo.class);
} catch (Exception ex) {
log.error("万达公众号token获取用户信息异-2!");
log.error(ex.getMessage(), ex);
return null;
}
}
}
...@@ -17,7 +17,9 @@ import javax.sql.DataSource; ...@@ -17,7 +17,9 @@ import javax.sql.DataSource;
*/ */
@Configuration @Configuration
@ConditionalOnClass(MybatisPlusConfig.class) @ConditionalOnClass(MybatisPlusConfig.class)
@MapperScan(basePackages = {"cn.sh.stc.sict.**.dao", "com.smarthealth.themestore.*.dao"}) @MapperScan(basePackages = {"cn.sh.stc.sict.**.dao",
"com.smarthealth.themestore.*.dao",
"cn.sh.stc.sict.**.**.dao"})
public class MybatisPlusConfig { public class MybatisPlusConfig {
/** /**
......
...@@ -13,6 +13,9 @@ import org.springframework.web.server.WebFilter; ...@@ -13,6 +13,9 @@ import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain; import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono; import reactor.core.publisher.Mono;
import java.util.HashSet;
import java.util.Set;
/** /**
* @Description * @Description
* @Author * @Author
...@@ -26,7 +29,17 @@ public class GlobalCorsConfig { ...@@ -26,7 +29,17 @@ public class GlobalCorsConfig {
*/ */
private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,access-token"; private static final String ALLOWED_HEADERS = "x-requested-with, authorization, Content-Type, Authorization, credential, X-XSRF-TOKEN,token,username,client,access-token";
private static final String ALLOWED_METHODS = "*"; private static final String ALLOWED_METHODS = "*";
private static final String ALLOWED_ORIGIN = "*"; private static final Set<String> ALLOWED_ORIGINS = new HashSet<String>(){{
add("https://inno.sh-sict.com");
add("https://hy.hpwjsns.org.cn");
add("http://localhost:12998");
add("http://127.0.0.1:12998");
add("http://sict-gateway:12998");
add("http://192.168.31.140:12998");
add("http://localhost:12999");
add("http://127.0.0.1:12999");
add("http://sict-gateway:12999");
}};
private static final String ALLOWED_Expose = "*"; private static final String ALLOWED_Expose = "*";
private static final String MAX_AGE = "18000L"; private static final String MAX_AGE = "18000L";
...@@ -37,7 +50,11 @@ public class GlobalCorsConfig { ...@@ -37,7 +50,11 @@ public class GlobalCorsConfig {
if (CorsUtils.isCorsRequest(request)) { if (CorsUtils.isCorsRequest(request)) {
ServerHttpResponse response = ctx.getResponse(); ServerHttpResponse response = ctx.getResponse();
HttpHeaders headers = response.getHeaders(); HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALLOWED_ORIGIN); if(ALLOWED_ORIGINS.contains(request.getHeaders().getOrigin())){
headers.add("Access-Control-Allow-Origin", request.getHeaders().getOrigin());
}else{
headers.add("Access-Control-Allow-Origin", "https://hy.hpwjsns.org.cn");
}
headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS); headers.add("Access-Control-Allow-Methods", ALLOWED_METHODS);
headers.add("Access-Control-Max-Age", MAX_AGE); headers.add("Access-Control-Max-Age", MAX_AGE);
headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS); headers.add("Access-Control-Allow-Headers", ALLOWED_HEADERS);
......
package cn.sh.stc.sict.cloud.common.gateway.config;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 网关不校验终端配置
* @Author
* @Date
*/
@Data
@Configuration
@RefreshScope
@ConditionalOnExpression("!'${whiteip}'.isEmpty()")
@ConfigurationProperties(prefix = "whiteip")
public class WhitIPConfig {
private Boolean limitFlag;
private List<String> whites = new ArrayList<>();
}
package cn.sh.stc.sict.cloud.common.gateway.feign;
import cn.sh.stc.sict.cloud.common.core.constant.ServiceNameConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.fallback.RemoteAuthFallback;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
/**
* @Description
* @Author
* @Date
*/
@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.AUTH_SERVICE, fallbackFactory = RemoteAuthFallback.class)
//@FeignClient(contextId = "remoteUserService", value = ServiceNameConstants.AUTH_SERVICE)
@Service
public interface RemoteAuthService {
/**
* 通过用户名或手机号查询用户
*
* @param username 用户名
* @param from 调用标志
* @return R
*/
@GetMapping("/token/check/{token}")
R<Boolean> isValid(@PathVariable("token") String token);
}
package cn.sh.stc.sict.cloud.common.gateway.feign.fallback;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.RemoteAuthService;
import feign.hystrix.FallbackFactory;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
/**
* @author gao
* @date 2023/09/04 09:51
*/
@Component
@Slf4j
public class RemoteAuthFallback implements FallbackFactory<RemoteAuthService> {
@Override
public RemoteAuthService create(Throwable throwable) {
return new RemoteAuthService() {
@Override
public R<Boolean> isValid(String toke) {
log.info("远程调用失败:权限校验错误");
return null;
}
};
}
}
package cn.sh.stc.sict.cloud.common.gateway.filter;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.gateway.feign.RemoteAuthService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
/**
* @author gao
* @date 2023/08/30 10:23
*/
@Slf4j
@Component
@AllArgsConstructor
public class GptServerFilter extends AbstractGatewayFilterFactory {
public final RemoteAuthService remoteAuthService;
public static final String SEC_WEBSOCKET_PROTOCOL = "Sec-WebSocket-Protocol";
@Override
public GatewayFilter apply(Object config) {
return (exchange, chain) -> {
ServerHttpRequest request = exchange.getRequest();
String token = request.getHeaders().getFirst(SEC_WEBSOCKET_PROTOCOL);
log.info("ws-token{}", token);
// 权限校验
if (checkToken(token)) {
return chain.filter(exchange);
} else {
return Mono.error(new RuntimeException("权限校验失败"));
}
};
}
/**
* 校验token
*
* @param token
* @return
*/
private boolean checkToken(String token) {
// if (StringUtils.isEmpty(token)) {
// return false;
// }
return true;
// R<Boolean> valid = remoteAuthService.isValid(token);
// if (ObjectUtil.isNull(valid) || ObjectUtil.isNull(valid.getData())) {
// return false;
// }
// return valid.getData();
}
}
...@@ -68,19 +68,19 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory { ...@@ -68,19 +68,19 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
} }
URI uri = exchange.getRequest().getURI(); URI uri = exchange.getRequest().getURI();
log.error("uri ==============>: {}", uri.toString()); // log.error("uri ==============>: {}", uri.toString());
String queryParam = uri.getRawQuery(); String queryParam = uri.getRawQuery();
log.error("queryParam==============>: {}", queryParam); // log.error("queryParam==============>: {}", queryParam);
Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8); Map<String, String> paramMap = HttpUtil.decodeParamMap(queryParam, CharsetUtil.UTF_8);
log.error("paramMap==============>: {}", paramMap.toString()); // log.error("paramMap==============>: {}", paramMap.toString());
String password = paramMap.get(PASSWORD); String password = paramMap.get(PASSWORD);
if (StrUtil.isNotBlank(password)) { if (StrUtil.isNotBlank(password)) {
try { try {
// password = decryptAES(password, encodeKey); // password = decryptAES(password, encodeKey);
log.error("before password: {}", password); // log.error("before password: {}", password);
password = CryptUtil.AESToString(password, encodeKey); password = CryptUtil.AESToString(password, encodeKey);
log.error("after password: {}", password); // log.error("after password: {}", password);
} catch (Exception e) { } catch (Exception e) {
log.error("密码解密失败:password = {}", password); log.error("密码解密失败:password = {}", password);
return Mono.error(e); return Mono.error(e);
...@@ -91,9 +91,9 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory { ...@@ -91,9 +91,9 @@ public class PasswordDecoderFilter extends AbstractGatewayFilterFactory {
if (StrUtil.isNotBlank(username)) { if (StrUtil.isNotBlank(username)) {
try { try {
// password = decryptAES(password, encodeKey); // password = decryptAES(password, encodeKey);
log.error("before username: {}", username); // log.error("before username: {}", username);
username = CryptUtil.AESToString(username, encodeKey); username = CryptUtil.AESToString(username, encodeKey);
log.error("after username: {}", username); // log.error("after username: {}", username);
} catch (Exception e) { } catch (Exception e) {
log.error("用户名解密失败:username = {}", username); log.error("用户名解密失败:username = {}", username);
return Mono.error(e); return Mono.error(e);
......
package cn.sh.stc.sict.cloud.common.gateway.filter; package cn.sh.stc.sict.cloud.common.gateway.filter;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants; import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.core.util.WebUtils;
import cn.sh.stc.sict.cloud.common.gateway.config.WhitIPConfig;
import cn.sh.stc.sict.cloud.common.gateway.util.IPStrUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.gateway.filter.GatewayFilterChain; import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter; import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered; import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils; import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange; import org.springframework.web.server.ServerWebExchange;
...@@ -17,8 +28,7 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G ...@@ -17,8 +28,7 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.G
import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl; import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.addOriginalRequestUrl;
/** /**
* @Description * @Description <p>
* <p>
* 全局拦截器,作用所有的微服务 * 全局拦截器,作用所有的微服务
* <p> * <p>
* 1. 对请求头中参数进行处理 from 参数进行清洗 * 1. 对请求头中参数进行处理 from 参数进行清洗
...@@ -28,9 +38,13 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.a ...@@ -28,9 +38,13 @@ import static org.springframework.cloud.gateway.support.ServerWebExchangeUtils.a
* @Author * @Author
* @Date * @Date
*/ */
@Slf4j
@Component @Component
@AllArgsConstructor
public class RequestGlobalFilter implements GlobalFilter, Ordered { public class RequestGlobalFilter implements GlobalFilter, Ordered {
private static final String HEADER_NAME = "X-Forwarded-Prefix"; private static final String HEADER_NAME = "X-Forwarded-Prefix";
private final WhitIPConfig whitIPConfig;
private final ObjectMapper objectMapper;
/** /**
* Process the Web request and (optionally) delegate to the next * Process the Web request and (optionally) delegate to the next
...@@ -44,9 +58,38 @@ public class RequestGlobalFilter implements GlobalFilter, Ordered { ...@@ -44,9 +58,38 @@ public class RequestGlobalFilter implements GlobalFilter, Ordered {
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 1. 清洗请求头中from 参数 // 1. 清洗请求头中from 参数
ServerHttpRequest request = exchange.getRequest().mutate() ServerHttpRequest request = exchange.getRequest().mutate()
.headers(httpHeaders -> {httpHeaders.remove(SecurityConstants.FROM);}) .headers(httpHeaders -> {
httpHeaders.remove(SecurityConstants.FROM);
})
.build(); .build();
// IP白名单
String ip = WebUtils.getIP(request);
// log.error("RemoteAddress = {}, ip = {}", request.getRemoteAddress(), ip);
try {
if (whitIPConfig.getLimitFlag() && !IPStrUtil.matches(ip, whitIPConfig.getWhites())) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg("没有权限访问")
.code(Constant.BYTE_NO).build()))));
}
} catch (
Exception e) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.PRECONDITION_REQUIRED);
response.getHeaders().set("Content-type", "application/json; charset=utf-8");
try {
return response.writeWith(Mono.just(response.bufferFactory()
.wrap(objectMapper.writeValueAsBytes(
R.builder().msg(e.getMessage())
.code(Constant.BYTE_NO).build()))));
} catch (JsonProcessingException e1) {
log.error("对象输出异常", e1);
}
}
// 2. 重写StripPrefix // 2. 重写StripPrefix
addOriginalRequestUrl(exchange, request.getURI()); addOriginalRequestUrl(exchange, request.getURI());
String rawPath = request.getURI().getRawPath(); String rawPath = request.getURI().getRawPath();
......
package cn.sh.stc.sict.cloud.common.gateway.util;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import java.util.List;
public class IPStrUtil {
static char START = '*';
/**
* 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, List<String> strs) {
if (StrUtil.isEmpty(str) || CollUtil.isEmpty(strs)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配指定字符串数组中的任意一个字符串
*
* @param str 指定字符串
* @param strs 需要检查的字符串数组
* @return 是否匹配
*/
public static boolean matches(String str, String... strs) {
if (StrUtil.isEmpty(str) || StrUtil.isAllEmpty(str)) {
return false;
}
for (String testStr : strs) {
if (matches(str, testStr)) {
return true;
}
}
return false;
}
/**
* 查找指定字符串是否匹配
*
* @param str 指定字符串
* @param pattern 需要检查的字符串
* @return 是否匹配
*/
public static boolean matches(String str, String pattern) {
if (StrUtil.isEmpty(pattern) || StrUtil.isEmpty(str)) {
return false;
}
pattern = pattern.replaceAll("\\s*", ""); // 替换空格
int beginOffset = 0; // pattern截取开始位置
int formerStarOffset = -1; // 前星号的偏移位置
int latterStarOffset = -1; // 后星号的偏移位置
String remainingURI = str;
String prefixPattern = "";
String suffixPattern = "";
boolean result = false;
do {
formerStarOffset = StrUtil.indexOf(pattern, START, beginOffset);
prefixPattern = StrUtil.sub(pattern, beginOffset, formerStarOffset > -1 ? formerStarOffset : pattern.length());
// 匹配前缀Pattern
result = remainingURI.contains(prefixPattern);
// 已经没有星号,直接返回
if (formerStarOffset == -1) {
return result;
}
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(prefixPattern)) {
remainingURI = StrUtil.subAfter(str, prefixPattern, true);
}
// 匹配后缀Pattern
latterStarOffset = StrUtil.indexOf(pattern, START, formerStarOffset + 1);
suffixPattern = StrUtil.sub(pattern, formerStarOffset + 1, latterStarOffset > -1 ? latterStarOffset : pattern.length());
result = remainingURI.contains(suffixPattern);
// 匹配失败,直接返回
if (!result)
return false;
if (!StrUtil.isEmpty(suffixPattern)) {
remainingURI = StrUtil.subAfter(str, suffixPattern, true);
}
// 移动指针
beginOffset = latterStarOffset + 1;
}
while (!StrUtil.isEmpty(suffixPattern) && !StrUtil.isEmpty(remainingURI));
return true;
}
@SuppressWarnings("unchecked")
public static <T> T cast(Object obj) {
return (T) obj;
}
}
...@@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j; ...@@ -7,6 +7,7 @@ import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException; import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException; import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.SpringSecurityMessageSource; import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.validation.BindException; import org.springframework.validation.BindException;
import org.springframework.validation.FieldError; import org.springframework.validation.FieldError;
...@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler; ...@@ -18,6 +19,7 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice; import org.springframework.web.bind.annotation.RestControllerAdvice;
import javax.security.auth.login.AccountLockedException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import javax.validation.ConstraintViolationException; import javax.validation.ConstraintViolationException;
import java.util.stream.Collectors; import java.util.stream.Collectors;
...@@ -77,6 +79,28 @@ public class GlobalExceptionHandlerResolver { ...@@ -77,6 +79,28 @@ public class GlobalExceptionHandlerResolver {
return objectR; return objectR;
} }
@ExceptionHandler({BadCredentialsException.class})
@ResponseStatus(HttpStatus.OK)
public R handleBadCredentialsException(BadCredentialsException exception) {
R<Object> objectR = R.builder()
.code(Constant.BYTE_NO)
.msg(exception.getMessage())
.build();
return objectR;
}
@ExceptionHandler({AccountLockedException.class})
@ResponseStatus(HttpStatus.OK)
public R handleBAccountLockedException(AccountLockedException exception) {
R<Object> objectR = R.builder()
.code(Constant.BYTE_NO)
.msg(exception.getMessage())
.build();
return objectR;
}
/** /**
* AccessDeniedException * AccessDeniedException
* *
......
...@@ -53,8 +53,10 @@ public class SictUserAuthenticationConverter implements UserAuthenticationConver ...@@ -53,8 +53,10 @@ public class SictUserAuthenticationConverter implements UserAuthenticationConver
String name = (String) map.get(SecurityConstants.DETAILS_NAME); String name = (String) map.get(SecurityConstants.DETAILS_NAME);
String openid = (String) map.get(SecurityConstants.DETAILS_OPENID); String openid = (String) map.get(SecurityConstants.DETAILS_OPENID);
String appid = (String) map.get(SecurityConstants.DETAILS_APPID); String appid = (String) map.get(SecurityConstants.DETAILS_APPID);
SictUser user = new SictUser(id, "", openid, appid, username, N_A, true String hospitalCode = (String) map.get(SecurityConstants.HOSPITAL_CODE);
, true, true, true, authorities); String xszyUserInfo = (String) map.get(SecurityConstants.XSZY_USER_INFO);
SictUser user = new SictUser(id, "", openid, appid, hospitalCode, username, N_A, true
, true, true, true, authorities, xszyUserInfo);
return new UsernamePasswordAuthenticationToken(user, N_A, authorities); return new UsernamePasswordAuthenticationToken(user, N_A, authorities);
} }
return null; return null;
......
...@@ -17,6 +17,8 @@ import org.springframework.security.oauth2.provider.error.WebResponseExceptionTr ...@@ -17,6 +17,8 @@ import org.springframework.security.oauth2.provider.error.WebResponseExceptionTr
import org.springframework.security.web.util.ThrowableAnalyzer; import org.springframework.security.web.util.ThrowableAnalyzer;
import org.springframework.web.HttpRequestMethodNotSupportedException; import org.springframework.web.HttpRequestMethodNotSupportedException;
import javax.security.auth.login.AccountLockedException;
/** /**
* @Description * @Description
* @Author * @Author
...@@ -33,8 +35,12 @@ public class SictWebResponseExceptionTranslator implements WebResponseExceptionT ...@@ -33,8 +35,12 @@ public class SictWebResponseExceptionTranslator implements WebResponseExceptionT
// Try to extract a SpringSecurityException from the stacktrace // Try to extract a SpringSecurityException from the stacktrace
Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e); Throwable[] causeChain = throwableAnalyzer.determineCauseChain(e);
Exception ase = (AccountLockedException) throwableAnalyzer.getFirstThrowableOfType(AccountLockedException.class, causeChain);
if(ase != null){
return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e, HttpStatus.LOCKED.value()));
}
Exception ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class, ase = (AuthenticationException) throwableAnalyzer.getFirstThrowableOfType(AuthenticationException.class,
causeChain); causeChain);
if (ase != null) { if (ase != null) {
return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e)); return handleOAuth2Exception(new UnauthorizedException(e.getMessage(), e));
......
package cn.sh.stc.sict.cloud.common.security.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import java.util.Locale;
//security中文提示信息配置类
@Configuration
public class ReloadMessageConfig {
@Bean //加载中文认证提示信息
public ReloadableResourceBundleMessageSource messageSource(){
Locale.setDefault(Locale.SIMPLIFIED_CHINESE);
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
//加载org/springframework/security包下的中文提示信息 配置文件
messageSource.setBasename("classpath:security/messages_zh_CN");
return messageSource;
}
}
package cn.sh.stc.sict.cloud.common.security.config;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import lombok.Data;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
/**
* 用户账号 配置属性
*/
@Data
@Component
@RefreshScope
@ConditionalOnExpression("!'${user}'.isEmpty()")
@ConfigurationProperties(prefix = "user.account")
public class UserAccountProperties {
private Boolean limitFlag;
private Long limitCount;
private Long limitTime;
public Boolean getLimitFlag() {
return !ObjectUtil.isNull(this.limitFlag) && this.limitFlag;
}
public Long getLimitCount(){
return NumberUtil.isNullOrZero(this.limitCount) ? 5L : this.limitCount;
}
public Long getLimitTime() {
return NumberUtil.isNullOrZero(this.limitTime) ? 30L : this.limitTime;
}
}
package cn.sh.stc.sict.cloud.common.security.exception; package cn.sh.stc.sict.cloud.common.security.exception;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.security.component.SictAuth2ExceptionSerializer; import cn.sh.stc.sict.cloud.common.security.component.SictAuth2ExceptionSerializer;
import com.fasterxml.jackson.databind.annotation.JsonSerialize; import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
/** /**
* @author lengleng * @author F_xh
* @date 2018/7/8 * @date 2018/7/8
*/ */
@JsonSerialize(using = SictAuth2ExceptionSerializer.class) @JsonSerialize(using = SictAuth2ExceptionSerializer.class)
public class UnauthorizedException extends SictAuth2Exception { public class UnauthorizedException extends SictAuth2Exception {
private Integer httpErrorCode;
public UnauthorizedException(String msg, Throwable t) { public UnauthorizedException(String msg, Throwable t) {
super(msg); super(msg);
} }
public UnauthorizedException(String msg, Throwable t, Integer httpErrorCode) {
super(msg);
this.httpErrorCode = httpErrorCode;
}
@Override @Override
public String getOAuth2ErrorCode() { public String getOAuth2ErrorCode() {
return "unauthorized"; return "unauthorized";
...@@ -22,7 +29,7 @@ public class UnauthorizedException extends SictAuth2Exception { ...@@ -22,7 +29,7 @@ public class UnauthorizedException extends SictAuth2Exception {
@Override @Override
public int getHttpErrorCode() { public int getHttpErrorCode() {
return HttpStatus.UNAUTHORIZED.value(); return NumberUtil.isNullOrZero(this.httpErrorCode) ? HttpStatus.UNAUTHORIZED.value() : this.httpErrorCode;
} }
} }
...@@ -54,7 +54,7 @@ public class SictFeignClientInterceptor extends OAuth2FeignRequestInterceptor { ...@@ -54,7 +54,7 @@ public class SictFeignClientInterceptor extends OAuth2FeignRequestInterceptor {
boolean isIngore = false; boolean isIngore = false;
if (CollectionUtil.isNotEmpty(permitAllUrlProperties.getIgnoreUrls())) { if (CollectionUtil.isNotEmpty(permitAllUrlProperties.getIgnoreUrls())) {
for (String ingoreUrl : permitAllUrlProperties.getIgnoreUrls()) { for (String ingoreUrl : permitAllUrlProperties.getIgnoreUrls()) {
if(template.url().startsWith(ingoreUrl.replace("*", ""))){ if(template.url().startsWith(ingoreUrl.replace("/**", ""))){
isIngore = true; isIngore = true;
break; break;
} }
......
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationFailureHandler {
/**
* 业务处理
* @param authenticationException 错误信息
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationLogoutHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.handler;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public interface AuthenticationSuccessHandler {
/**
* 业务处理
* @param authentication 认证信息
* @param request 请求信息
* @param response 响应信息
*/
void handle(Authentication authentication, HttpServletRequest request, HttpServletResponse response);
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationFailureEvent;
import org.springframework.security.authentication.event.AuthenticationFailureProviderNotFoundEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationFailureEventListener implements ApplicationListener<AbstractAuthenticationFailureEvent> {
@Autowired(required = false)
private List<AuthenticationFailureHandler> failureHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationFailureEvent event) {
// 此类型事件不传递处理 #2386
if (event instanceof AuthenticationFailureProviderNotFoundEvent) {
return;
}
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
AuthenticationException authenticationException = event.getException();
Authentication authentication = (Authentication) event.getSource();
// 调用自定义业务链实现
if (CollUtil.isNotEmpty(failureHandlerList)) {
failureHandlerList.forEach(failureHandler -> failureHandler.handle(authenticationException, authentication,
request, response));
}
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationLogoutHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AbstractAuthenticationEvent;
import org.springframework.security.core.Authentication;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AuthenticationLogoutSuccessEventListener implements ApplicationListener<AbstractAuthenticationEvent> {
@Autowired(required = false)
private AuthenticationLogoutHandler logoutHandler;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AbstractAuthenticationEvent event) {
// 健壮性判断
if (!(event.getSource() instanceof OAuth2Authentication)) {
return;
}
OAuth2Authentication authentication = (OAuth2Authentication) event.getSource();
if (logoutHandler != null && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
logoutHandler.handle(authentication, request, response);
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
package cn.sh.stc.sict.cloud.common.security.listener;
import cn.hutool.core.collection.CollUtil;
import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationSuccessHandler;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationListener;
import org.springframework.security.authentication.event.AuthenticationSuccessEvent;
import org.springframework.security.core.Authentication;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
public class AuthenticationSuccessEventListener implements ApplicationListener<AuthenticationSuccessEvent> {
@Autowired(required = false)
private List<AuthenticationSuccessHandler> successHandlerList;
/**
* Handle an application event.
* @param event the event to respond to
*/
@Override
public void onApplicationEvent(AuthenticationSuccessEvent event) {
Authentication authentication = (Authentication) event.getSource();
if (CollUtil.isNotEmpty(successHandlerList) && isUserAuthentication(authentication)) {
ServletRequestAttributes requestAttributes = (ServletRequestAttributes) RequestContextHolder
.getRequestAttributes();
HttpServletRequest request = requestAttributes.getRequest();
HttpServletResponse response = requestAttributes.getResponse();
successHandlerList.forEach(successHandler -> successHandler.handle(authentication, request, response));
}
}
private boolean isUserAuthentication(Authentication authentication) {
return authentication.getPrincipal() instanceof SictUser
|| CollUtil.isNotEmpty(authentication.getAuthorities());
}
}
...@@ -35,6 +35,17 @@ public class SictUser extends User { ...@@ -35,6 +35,17 @@ public class SictUser extends User {
@Setter @Setter
private String appId; private String appId;
/**
* 医院公众号登陆的用户包含医院代码
*/
@Getter
@Setter
private String hospitalCode;
@Getter
@Setter
private String xszyUserInfo;
@Getter @Getter
@Setter @Setter
private transient String token; private transient String token;
...@@ -44,6 +55,7 @@ public class SictUser extends User { ...@@ -44,6 +55,7 @@ public class SictUser extends User {
* {@link DaoAuthenticationProvider}. * {@link DaoAuthenticationProvider}.
* *
* @param id 用户ID * @param id 用户ID
* @param hospitalCode 医院代码
* @param username the username presented to the * @param username the username presented to the
* <code>DaoAuthenticationProvider</code> * <code>DaoAuthenticationProvider</code>
* @param password the password that should be presented to the * @param password the password that should be presented to the
...@@ -58,11 +70,25 @@ public class SictUser extends User { ...@@ -58,11 +70,25 @@ public class SictUser extends User {
* @throws IllegalArgumentException if a <code>null</code> value was passed either as * @throws IllegalArgumentException if a <code>null</code> value was passed either as
* a parameter or as an element in the <code>GrantedAuthority</code> collection * a parameter or as an element in the <code>GrantedAuthority</code> collection
*/ */
public SictUser(Long id, String phone, String openId, String appId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { public SictUser(Long id,
String phone,
String openId,
String appId,
String hospitalCode,
String username,
String password,
boolean enabled,
boolean accountNonExpired,
boolean credentialsNonExpired,
boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities,
String xszyUserInfo) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.id = id; this.id = id;
this.phone = phone; this.phone = phone;
this.openId = openId; this.openId = openId;
this.appId = appId; this.appId = appId;
this.hospitalCode = hospitalCode;
this.xszyUserInfo = xszyUserInfo;
} }
} }
...@@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil; ...@@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant; import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant; import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants; import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties;
import cn.sh.stc.sict.cloud.common.security.util.AuthUtils; import cn.sh.stc.sict.cloud.common.security.util.AuthUtils;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo; import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService; import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
...@@ -16,6 +18,7 @@ import lombok.SneakyThrows; ...@@ -16,6 +18,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
...@@ -26,6 +29,7 @@ import org.springframework.stereotype.Service; ...@@ -26,6 +29,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.security.auth.login.AccountLockedException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
...@@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
private static final String BASIC_ = "Basic "; private static final String BASIC_ = "Basic ";
private final RemoteUserService remoteUserService; private final RemoteUserService remoteUserService;
private final CacheManager cacheManager; private final CacheManager cacheManager;
private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
/** /**
* 用户密码登录 * 用户密码登录
* .
* *
* @param username 用户名 * @param username 用户名
* @return * @return
...@@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
@SneakyThrows @SneakyThrows
public UserDetails loadUserByUsername(String username) { public UserDetails loadUserByUsername(String username) {
String key = username; String key = username;
String lockedKey = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long times = NumberUtil.getLongValue(redisTemplate.opsForValue().get(lockedKey));
if (userAccountProperties.getLimitFlag() && times >= userAccountProperties.getLimitCount()) {
throw new AccountLockedException("账号被锁定");
}
Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS); Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS);
if (!StrUtil.containsAny(key, StringPool.COLON)) { if (!StrUtil.containsAny(key, StringPool.COLON)) {
key = key + StringPool.COLON + getAppId(); key = key + StringPool.COLON + getAppId();
...@@ -117,11 +129,17 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -117,11 +129,17 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
if (StrUtil.isBlank(user.getUserName())) { if (StrUtil.isBlank(user.getUserName())) {
user.setUserName(user.getId().toString()); user.setUserName(user.getId().toString());
} }
String userName = user.getUserName() + StringPool.COLON + info.getAppId(); String userName = user.getUserName() + StringPool.COLON + info.getAppId();
return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, SecurityConstants.BCRYPT + user.getPasswd(), enabled, if (StrUtil.isNotBlank(info.getHospitalCode())) {
true, true, !Constant.BYTE_YES.equals(user.getStatus()), authorities); userName = userName.concat(StringPool.COLON).concat(info.getHospitalCode());
} }
String password = SecurityConstants.BCRYPT + user.getPasswd();
// 登录失败5次锁定半小时
boolean nonLockd = !Constant.BYTE_YES.equals(user.getStatus());
return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), info.getHospitalCode(), userName, password, enabled,
true, true, nonLockd, authorities, info.getXszyUserInfo());
}
private static String getAppId() { private static String getAppId() {
String appId = ""; String appId = "";
......
...@@ -178,6 +178,9 @@ public class SecurityUtils { ...@@ -178,6 +178,9 @@ public class SecurityUtils {
current.setName(StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName()); current.setName(StrUtil.isBlank(user.getName()) ? user.getUsername() : user.getName());
current.setOpenId(user.getOpenId()); current.setOpenId(user.getOpenId());
current.setAppId(user.getAppId()); current.setAppId(user.getAppId());
current.setPhone(user.getPhone());
current.setHospitalCode(user.getHospitalCode());
current.setXszyUserInfo(user.getXszyUserInfo());
} }
current.setToken(token); current.setToken(token);
return current; return current;
......
...@@ -57,6 +57,19 @@ public class SysLogUtils { ...@@ -57,6 +57,19 @@ public class SysLogUtils {
return sysLog; return sysLog;
} }
public SysLog getSysLog(HttpServletRequest request, String username) {
SysLog sysLog = new SysLog();
sysLog.setCreateBy(username);
sysLog.setType(Constant.BYTE_NO);
sysLog.setRemoteAddr(ServletUtil.getClientIP(request));
sysLog.setRequestUri(URLUtil.getPath(request.getRequestURI()));
sysLog.setMethod(request.getMethod());
sysLog.setUserAgent(request.getHeader("user-agent"));
sysLog.setParams(HttpUtil.toParams(request.getParameterMap()));
sysLog.setServiceId("/cloud-auth");
return sysLog;
}
public static Map<String, Object> getKeyAndValue(Object obj) { public static Map<String, Object> getKeyAndValue(Object obj) {
Map<String, Object> map = new HashMap<>(); Map<String, Object> map = new HashMap<>();
try { try {
......
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\ org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\
cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\ cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties,\
cn.sh.stc.sict.cloud.common.security.config.ReloadMessageConfig,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl,\
cn.sh.stc.sict.cloud.common.security.component.SictWebResponseExceptionTranslator,\
cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationFailureEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationSuccessEventListener,\
cn.sh.stc.sict.cloud.common.security.listener.AuthenticationLogoutSuccessEventListener
AbstractAccessDecisionManager.accessDenied=Access is denied
AbstractLdapAuthenticationProvider.emptyPassword=Empty Password
AbstractSecurityInterceptor.authenticationNotFound=An Authentication object was not found in the SecurityContext
AbstractUserDetailsAuthenticationProvider.badCredentials=Bad credentials
AbstractUserDetailsAuthenticationProvider.credentialsExpired=User credentials have expired
AbstractUserDetailsAuthenticationProvider.disabled=User is disabled
AbstractUserDetailsAuthenticationProvider.expired=User account has expired
AbstractUserDetailsAuthenticationProvider.locked=User account is locked
AbstractUserDetailsAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
AccountStatusUserDetailsChecker.credentialsExpired=User credentials have expired
AccountStatusUserDetailsChecker.disabled=User is disabled
AccountStatusUserDetailsChecker.expired=User account has expired
AccountStatusUserDetailsChecker.locked=User account is locked
AclEntryAfterInvocationProvider.noPermission=Authentication {0} has NO permissions to the domain object {1}
AnonymousAuthenticationProvider.incorrectKey=The presented AnonymousAuthenticationToken does not contain the expected key
BindAuthenticator.badCredentials=Bad credentials
BindAuthenticator.emptyPassword=Empty Password
CasAuthenticationProvider.incorrectKey=The presented CasAuthenticationToken does not contain the expected key
CasAuthenticationProvider.noServiceTicket=Failed to provide a CAS service ticket to validate
ConcurrentSessionControlAuthenticationStrategy.exceededAllowed=Maximum sessions of {0} for this principal exceeded
DigestAuthenticationFilter.incorrectRealm=Response realm name {0} does not match system realm name of {1}
DigestAuthenticationFilter.incorrectResponse=Incorrect response
DigestAuthenticationFilter.missingAuth=Missing mandatory digest value for 'auth' QOP; received header {0}
DigestAuthenticationFilter.missingMandatory=Missing mandatory digest value; received header {0}
DigestAuthenticationFilter.nonceCompromised=Nonce token compromised {0}
DigestAuthenticationFilter.nonceEncoding=Nonce is not encoded in Base64; received nonce {0}
DigestAuthenticationFilter.nonceExpired=Nonce has expired/timed out
DigestAuthenticationFilter.nonceNotNumeric=Nonce token should have yielded a numeric first token, but was {0}
DigestAuthenticationFilter.nonceNotTwoTokens=Nonce should have yielded two tokens but was {0}
DigestAuthenticationFilter.usernameNotFound=Username {0} not found
JdbcDaoImpl.noAuthority=User {0} has no GrantedAuthority
JdbcDaoImpl.notFound=User {0} not found
LdapAuthenticationProvider.badCredentials=Bad credentials
LdapAuthenticationProvider.credentialsExpired=User credentials have expired
LdapAuthenticationProvider.disabled=User is disabled
LdapAuthenticationProvider.expired=User account has expired
LdapAuthenticationProvider.locked=User account is locked
LdapAuthenticationProvider.emptyUsername=Empty username not allowed
LdapAuthenticationProvider.onlySupports=Only UsernamePasswordAuthenticationToken is supported
PasswordComparisonAuthenticator.badCredentials=Bad credentials
PersistentTokenBasedRememberMeServices.cookieStolen=Invalid remember-me token (Series/token) mismatch. Implies previous cookie theft attack.
ProviderManager.providerNotFound=No AuthenticationProvider found for {0}
RememberMeAuthenticationProvider.incorrectKey=The presented RememberMeAuthenticationToken does not contain the expected key
RunAsImplAuthenticationProvider.incorrectKey=The presented RunAsUserToken does not contain the expected key
SubjectDnX509PrincipalExtractor.noMatching=No matching pattern was found in subjectDN: {0}
SwitchUserFilter.noCurrentUser=No current user associated with this request
SwitchUserFilter.noOriginalAuthentication=Could not find original Authentication object
...@@ -3,6 +3,7 @@ package cn.sh.stc.sict.cloud.gateway; ...@@ -3,6 +3,7 @@ package cn.sh.stc.sict.cloud.gateway;
import cn.sh.stc.sict.cloud.common.dynamic.gateway.annotation.EnableDynamicRoute; import cn.sh.stc.sict.cloud.common.dynamic.gateway.annotation.EnableDynamicRoute;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
/** /**
* @Description * @Description
...@@ -11,6 +12,7 @@ import org.springframework.cloud.client.SpringCloudApplication; ...@@ -11,6 +12,7 @@ import org.springframework.cloud.client.SpringCloudApplication;
*/ */
@EnableDynamicRoute @EnableDynamicRoute
@SpringCloudApplication @SpringCloudApplication
@EnableFeignClients(basePackages = {"cn.sh.stc.sict.cloud.common.gateway.feign"})
public class SictGatewayApplication { public class SictGatewayApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(SictGatewayApplication.class, args); SpringApplication.run(SictGatewayApplication.class, args);
......
...@@ -9,9 +9,9 @@ spring: ...@@ -9,9 +9,9 @@ spring:
nacos: nacos:
server-addr: 127.0.0.1:8848 server-addr: 127.0.0.1:8848
discovery: discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config: config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles: profiles:
......
server:
port: 12998
spring:
application:
name: @artifactId@
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
active: dev
logging:
config: classpath:logback-spring.xml
file:
name: ../logs/${spring.application.name}/console.log
...@@ -63,7 +63,7 @@ ...@@ -63,7 +63,7 @@
<appender-ref ref="error"/> <appender-ref ref="error"/>
</logger> </logger>
<!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 --> <!-- Level: FATAL 0 ERROR 3 WARN 4 INFO 6 DEBUG 7 -->
<root level="INFO"> <root level="ERROR">
<appender-ref ref="console"/> <appender-ref ref="console"/>
<appender-ref ref="debug"/> <appender-ref ref="debug"/>
</root> </root>
......
...@@ -171,6 +171,9 @@ ...@@ -171,6 +171,9 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId> <artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version> <version>${spring-boot.version}</version>
<configuration>
<includeSystemScope>true</includeSystemScope>
</configuration>
<executions> <executions>
<execution> <execution>
<goals> <goals>
......
package cn.sh.stc.sict.cloud.upms.dto; package cn.sh.stc.sict.cloud.upms.dto;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import lombok.Data; import lombok.Data;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
import java.util.List;
/** /**
* @Description 当前登陆人信息 * @Description 当前登陆人信息
...@@ -19,6 +22,10 @@ public class CurrentUser implements Serializable { ...@@ -19,6 +22,10 @@ public class CurrentUser implements Serializable {
private String appId; private String appId;
private String idNum; private String idNum;
private String phone; private String phone;
/**
* 医院公众号登陆的用户包含医院代码
*/
private String hospitalCode;
private Date createTime; private Date createTime;
private Byte gender; private Byte gender;
private Date registerTime; private Date registerTime;
...@@ -26,5 +33,14 @@ public class CurrentUser implements Serializable { ...@@ -26,5 +33,14 @@ public class CurrentUser implements Serializable {
* sict_admin * sict_admin
*/ */
private String adminStr; private String adminStr;
/**
* 香山中医公众号用户信息
*/
private String xszyUserInfo;
/**
* 机器人问答
*/
private String qaHistory;
} }
...@@ -12,8 +12,24 @@ import lombok.Data; ...@@ -12,8 +12,24 @@ import lombok.Data;
@Data @Data
public class UserInfo { public class UserInfo {
/**
* 登陆人openId
*/
private String openId; private String openId;
/**
* 登陆人公众号appdId
*/
private String appId; private String appId;
/**
* 医院公众号登陆的用户包含医院代码
*/
private String hospitalCode;
/**
* 香山中医公众号用户信息
*/
private String xszyUserInfo;
/** /**
* 用户基本信息 * 用户基本信息
*/ */
......
...@@ -32,6 +32,11 @@ public class SysUserBase extends Model<SysUserBase> { ...@@ -32,6 +32,11 @@ public class SysUserBase extends Model<SysUserBase> {
@ApiModelProperty(value = "用户id") @ApiModelProperty(value = "用户id")
private Long id; private Long id;
/**
* 公众号appId
*/
private String appId;
private String openId; private String openId;
/** /**
...@@ -90,6 +95,11 @@ public class SysUserBase extends Model<SysUserBase> { ...@@ -90,6 +95,11 @@ public class SysUserBase extends Model<SysUserBase> {
*/ */
@ApiModelProperty(hidden = true, value = "账号状态:0-正常,1-禁用") @ApiModelProperty(hidden = true, value = "账号状态:0-正常,1-禁用")
private Byte status; private Byte status;
/**
* 来源
*/
private String source;
/** /**
* *
*/ */
...@@ -137,6 +147,8 @@ public class SysUserBase extends Model<SysUserBase> { ...@@ -137,6 +147,8 @@ public class SysUserBase extends Model<SysUserBase> {
@ApiModelProperty(hidden = true, value = "") @ApiModelProperty(hidden = true, value = "")
private Date updateTime; private Date updateTime;
private Date lastPwdTime;
/** /**
* 主键值 * 主键值
*/ */
......
package cn.sh.stc.sict.cloud.upms.config;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.stereotype.Component;
import java.util.Date;
/**
* 用户密码修改提示 配置属性
*/
@Data
@Component
@RefreshScope
@ConfigurationProperties(prefix = "user.pwd")
public class UserPwdProperties {
/**
* 是否进行密码修改提示
*/
private Boolean limitFlag;
/**
* 上次修改超过{{limitDays}}天,锁定用户
*/
private Integer limitDays;
/**
* 上次修改超过{{tipsDays}}天,开始提示用户修改密码
*/
private Integer tipsDays;
public boolean getTips(Date lastPwdTime) {
long offsetDays = DateUtil.betweenDay(lastPwdTime, DateUtil.date(), true);
if (offsetDays > tipsDays) {
return true;
}
return false;
}
}
package cn.sh.stc.sict.cloud.upms.controller.feign;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.upms.model.SysLog;
import cn.sh.stc.sict.cloud.upms.service.SysLogService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
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;
/**
* 系统日志
*
* @author F_xh。
* @date 2020-12-27 11:34:55
*/
@Slf4j
@RestController
@RequestMapping("/feign/log")
@AllArgsConstructor
public class LogFeignController {
private final SysLogService sysLogService;
@PostMapping("/save")
private R<Boolean> saveLog(@RequestBody SysLog sysLog){
sysLogService.save(sysLog);
return new R(true);
}
}
...@@ -5,8 +5,9 @@ import cn.sh.stc.sict.cloud.common.core.util.R; ...@@ -5,8 +5,9 @@ import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.annotation.Inner; import cn.sh.stc.sict.cloud.common.security.annotation.Inner;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo; import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.service.SysUserBaseService; import cn.sh.stc.sict.cloud.upms.service.SysUserBaseService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
...@@ -20,12 +21,14 @@ import org.springframework.web.bind.annotation.RestController; ...@@ -20,12 +21,14 @@ import org.springframework.web.bind.annotation.RestController;
@Slf4j @Slf4j
@RestController @RestController
@RequestMapping("/feign/user/base") @RequestMapping("/feign/user/base")
@AllArgsConstructor
public class UserFeignController { public class UserFeignController {
@Autowired
private SysUserBaseService sysUserBaseService; private SysUserBaseService sysUserBaseService;
@Value("${default.sso.user:systemadmin}")
private String defaultSSOUser;
/** /**
* F_xh 根据用户名获取用户登录信息 * F_xh 根据用户名获取用户登录信息
*
* @param username * @param username
* @return * @return
*/ */
...@@ -38,17 +41,22 @@ public class UserFeignController { ...@@ -38,17 +41,22 @@ public class UserFeignController {
} }
/** /**
* F_xh 根据移动端 inStr 获取用户登录信息 * F_xh 根据移动端 inStr 获取用户登录信息
*
* @return * @return
*/ */
@Inner @Inner
@GetMapping("/social/info/{appId}/{inStr}") @GetMapping("/social/info/{appId}/{inStr}")
public R social(@PathVariable("appId") String appId, public R social(@PathVariable("appId") String appId,
@PathVariable("inStr") String inStr){ @PathVariable("inStr") String inStr) {
try { try {
UserInfo info = sysUserBaseService.getUserInfoBySocial(appId, inStr); UserInfo info = new UserInfo();
if (inStr.contains("cs@token")) {
info = sysUserBaseService.getUserInfo(appId, defaultSSOUser);
} else {
info = sysUserBaseService.getUserInfoBySocial(appId, inStr);
}
return new R().success(info); return new R().success(info);
} catch (Exception e) { } catch (Exception e) {
e.printStackTrace(); e.printStackTrace();
......
package cn.sh.stc.sict.cloud.upms.controller.web; package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.upms.service.HpRoleMenuService; import cn.sh.stc.sict.cloud.upms.service.HpRoleMenuService;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -39,6 +41,7 @@ public class HpMenuController { ...@@ -39,6 +41,7 @@ public class HpMenuController {
*/ */
@ApiOperation("分页查询 系统菜单表") @ApiOperation("分页查询 系统菜单表")
@GetMapping("/page") @GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getHpMenuPage(Page page, HpMenu hpMenu) { public R getHpMenuPage(Page page, HpMenu hpMenu) {
return new R<>(hpMenuService.page(page, Wrappers.query(hpMenu))); return new R<>(hpMenuService.page(page, Wrappers.query(hpMenu)));
} }
...@@ -61,8 +64,10 @@ public class HpMenuController { ...@@ -61,8 +64,10 @@ public class HpMenuController {
* @param hpMenu 系统菜单表 * @param hpMenu 系统菜单表
* @return R * @return R
*/ */
@SysLog
@ApiOperation("新增系统菜单表") @ApiOperation("新增系统菜单表")
@PostMapping @PostMapping
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R save(@RequestBody HpMenu hpMenu) { public R save(@RequestBody HpMenu hpMenu) {
hpMenuService.saveOrUpdate(hpMenu); hpMenuService.saveOrUpdate(hpMenu);
return new R<>(); return new R<>();
...@@ -73,8 +78,10 @@ public class HpMenuController { ...@@ -73,8 +78,10 @@ public class HpMenuController {
* *
* @return R * @return R
*/ */
@SysLog
@ApiOperation("删除系统菜单表") @ApiOperation("删除系统菜单表")
@DeleteMapping("/{menuId}") @DeleteMapping("/{menuId}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R removeById(@PathVariable Long menuId) { public R removeById(@PathVariable Long menuId) {
if (hpRoleMenuService.exist(menuId)) { if (hpRoleMenuService.exist(menuId)) {
return new R().error("不可删除!"); return new R().error("不可删除!");
......
package cn.sh.stc.sict.cloud.upms.controller.web; package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.upms.dto.RoleDTO; import cn.sh.stc.sict.cloud.upms.dto.RoleDTO;
import cn.sh.stc.sict.cloud.upms.model.HpMenu; import cn.sh.stc.sict.cloud.upms.model.HpMenu;
import cn.sh.stc.sict.cloud.upms.model.HpRole; import cn.sh.stc.sict.cloud.upms.model.HpRole;
...@@ -14,8 +15,10 @@ import io.swagger.annotations.Api; ...@@ -14,8 +15,10 @@ import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletRequest;
import java.util.List; import java.util.List;
...@@ -46,6 +49,7 @@ public class HpRoleController { ...@@ -46,6 +49,7 @@ public class HpRoleController {
*/ */
@ApiOperation("分页查询 系统角色表") @ApiOperation("分页查询 系统角色表")
@GetMapping("/page") @GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getHpRolePage(Page page, HpRole hpRole) { public R getHpRolePage(Page page, HpRole hpRole) {
return new R<>(hpRoleService.page(page, Wrappers.query(hpRole))); return new R<>(hpRoleService.page(page, Wrappers.query(hpRole)));
} }
...@@ -70,15 +74,19 @@ public class HpRoleController { ...@@ -70,15 +74,19 @@ public class HpRoleController {
return new R<>(dto); return new R<>(dto);
} }
@SysLog
@ApiOperation("新增/修改系统角色") @ApiOperation("新增/修改系统角色")
@PostMapping @PostMapping
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R save(@RequestBody RoleDTO dto) { public R save(@RequestBody RoleDTO dto) {
hpRoleService.saveDto(dto); hpRoleService.saveDto(dto);
return new R<>(); return new R<>();
} }
@SysLog
@ApiOperation("删除系统角色表") @ApiOperation("删除系统角色表")
@DeleteMapping("/{id}") @DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R removeById(@PathVariable Long id) { public R removeById(@PathVariable Long id) {
// 判断是否可删除 // 判断是否可删除
if(hpUserRoleService.exist(id)){ if(hpUserRoleService.exist(id)){
......
package cn.sh.stc.sict.cloud.upms.controller.web; package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.upms.model.SysLog; import cn.sh.stc.sict.cloud.upms.model.SysLog;
import cn.sh.stc.sict.cloud.upms.service.SysLogService; import cn.sh.stc.sict.cloud.upms.service.SysLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
...@@ -29,6 +31,7 @@ public class SysLogController { ...@@ -29,6 +31,7 @@ public class SysLogController {
/** /**
* 分页查询 * 分页查询
*
* @param page 分页对象 * @param page 分页对象
* @param sysLog 系统日志 * @param sysLog 系统日志
* @return * @return
...@@ -36,17 +39,23 @@ public class SysLogController { ...@@ -36,17 +39,23 @@ public class SysLogController {
@ApiOperation("分页查询 系统日志") @ApiOperation("分页查询 系统日志")
@GetMapping("/page") @GetMapping("/page")
public R getSysLogPage(Page page, SysLog sysLog) { public R getSysLogPage(Page page, SysLog sysLog) {
return new R<>(sysLogService.page(page,Wrappers.query(sysLog))); LambdaQueryWrapper<SysLog> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(sysLog.getTitle()), SysLog::getTitle, sysLog.getTitle())
.like(StrUtil.isNotBlank(sysLog.getMethod()), SysLog::getMethod, sysLog.getMethod())
.like(StrUtil.isNotBlank(sysLog.getParams()), SysLog::getParams, sysLog.getParams())
.orderByDesc(SysLog::getCreateTime);
return new R<>(sysLogService.page(page, wrapper));
} }
/** /**
* 通过id查询系统日志 * 通过id查询系统日志
*
* @param id id * @param id id
* @return R * @return R
*/ */
@ApiOperation("通过id查询 系统日志") @ApiOperation("通过id查询 系统日志")
@GetMapping("/{id}") @GetMapping("/{id}")
public R getById(@PathVariable("id") Long id){ public R getById(@PathVariable("id") Long id) {
return new R<>(sysLogService.getById(id)); return new R<>(sysLogService.getById(id));
} }
......
package cn.sh.stc.sict.cloud.upms.controller.web; package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant; import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.enums.BizCodeConstant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil; import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.service.SictUser;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils; import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.config.UserPwdProperties;
import cn.sh.stc.sict.cloud.upms.dto.ChangePasswordDTO;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser; import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.cloud.upms.dto.UserDTO; import cn.sh.stc.sict.cloud.upms.dto.UserDTO;
import cn.sh.stc.sict.cloud.upms.model.HpMenu; import cn.sh.stc.sict.cloud.upms.model.HpMenu;
...@@ -17,6 +24,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; ...@@ -17,6 +24,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import io.swagger.annotations.Api; import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation; import io.swagger.annotations.ApiOperation;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
...@@ -50,30 +58,37 @@ public class SysUserBaseController { ...@@ -50,30 +58,37 @@ public class SysUserBaseController {
* 3. 角色配置 * 3. 角色配置
* 4. 重置密码(加密处理) * 4. 重置密码(加密处理)
*/ */
private SysUserBaseService sysUserBaseService; private final SysUserBaseService sysUserBaseService;
private HpRoleService hpRoleService; private final HpRoleService hpRoleService;
private HpUserRoleService hpUserRoleService; private final HpUserRoleService hpUserRoleService;
private HpMenuService hpMenuService; private final HpMenuService hpMenuService;
private final UserPwdProperties userPwdProperties;
private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder(); private static final PasswordEncoder ENCODER = new BCryptPasswordEncoder();
@ApiOperation("分页查询 系统基础用户表") @ApiOperation("分页查询 系统基础用户表")
@GetMapping("/page") @GetMapping("/page")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R getSysUserBasePage(Page page, SysUserBase sysUserBase) { public R getSysUserBasePage(Page page, SysUserBase sysUserBase) {
return new R<>(sysUserBaseService.page(page, Wrappers.query(sysUserBase))); return new R<>(sysUserBaseService.page(page, Wrappers.query(sysUserBase)));
} }
@SysLog
@ApiOperation("新增/修改用户") @ApiOperation("新增/修改用户")
@PostMapping @PostMapping
public R save(@RequestBody SysUserBase userBase) { @PreAuthorize("@pms.hasPermission('ROLE_admin')")
if (NumberUtil.isNullOrZero(userBase.getId())) { public R save(@RequestBody SysUserBase user) {
if(StrUtil.isBlank(userBase.getUserName())){ if (NumberUtil.isNullOrZero(user.getId())) {
if (StrUtil.isBlank(user.getUserName())) {
return new R().error("用户名不可为空!"); return new R().error("用户名不可为空!");
} }
String pw = StrUtil.isBlank(userBase.getPasswd()) ? Constant.DEFAULT_PASSWORD : userBase.getPasswd(); String pw = StrUtil.isBlank(user.getPasswd()) ? Constant.DEFAULT_PASSWORD : user.getPasswd();
userBase.setPasswd(ENCODER.encode(pw)); user.setPasswd(ENCODER.encode(pw));
} }
userBase.setStatus(Constant.BYTE_NO); if (sysUserBaseService.exist(user)) {
sysUserBaseService.saveOrUpdate(userBase); return new R().error("相同用户名用户已经存在!");
}
user.setStatus(Constant.BYTE_NO);
sysUserBaseService.saveOrUpdate(user);
return new R<>(); return new R<>();
} }
...@@ -94,7 +109,7 @@ public class SysUserBaseController { ...@@ -94,7 +109,7 @@ public class SysUserBaseController {
@ApiOperation("获取当前用户信息") @ApiOperation("获取当前用户信息")
@GetMapping("/info/current") @GetMapping("/info/current")
public R getCurrentUserInfo(){ public R getCurrentUserInfo() {
CurrentUser current = SecurityUtils.getCurrentUser(); CurrentUser current = SecurityUtils.getCurrentUser();
if (current == null) { if (current == null) {
return new R().error("无登录信息!"); return new R().error("无登录信息!");
...@@ -109,13 +124,18 @@ public class SysUserBaseController { ...@@ -109,13 +124,18 @@ public class SysUserBaseController {
dto.setUser(user); dto.setUser(user);
dto.setRoleList(roleList); dto.setRoleList(roleList);
dto.setMenuList(menuList); dto.setMenuList(menuList);
if (userPwdProperties.getLimitFlag() && ObjectUtil.isNotNull(user.getLastPwdTime()) && userPwdProperties.getTips(user.getLastPwdTime())) {
return new R(dto).setBizCode(BizCodeConstant.USER_PWD_LIMIT.getCode());
} else {
return new R(dto); return new R(dto);
} }
}
@SysLog
@ApiOperation("设置用户角色信息") @ApiOperation("设置用户角色信息")
@PostMapping("/role") @PostMapping("/role")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R saveUserRole(@RequestBody UserDTO dto) { public R saveUserRole(@RequestBody UserDTO dto) {
if (NumberUtil.isNullOrZero(dto.getUser().getId())) { if (NumberUtil.isNullOrZero(dto.getUser().getId())) {
return new R().error("用户id不可为空!"); return new R().error("用户id不可为空!");
...@@ -124,13 +144,63 @@ public class SysUserBaseController { ...@@ -124,13 +144,63 @@ public class SysUserBaseController {
return new R(); return new R();
} }
@SysLog
@ApiOperation("修改用户密码")
@PutMapping("/password")
public R<?> changePassword(@RequestBody ChangePasswordDTO password) {
if (StrUtil.isBlank(password.getNewPassword()) || StrUtil.isBlank(password.getOldPassword())) {
return new R<>().error("新密码或旧密码不能为空!");
}
if (StrUtil.equals(password.getNewPassword(), password.getOldPassword())) {
return new R<>().error("新密码不能与旧密码相同!");
}
SictUser user = SecurityUtils.getUser();
SysUserBase userBase = sysUserBaseService.getById(user.getId());
if (userBase == null) {
return new R<>().error("用户不存在!");
}
if (!ENCODER.matches(password.getOldPassword(), userBase.getPasswd())) {
return new R<>().error("旧密码不正确!");
}
userBase.setPasswd(ENCODER.encode(password.getNewPassword()));
userBase.setLastPwdTime(DateUtil.date());
sysUserBaseService.updateById(userBase);
sysUserBaseService.initRedisByUserName(userBase.getUserName());
return new R<>().success("");
}
@SysLog
@ApiOperation("重置密码")
@PutMapping("/reset/password")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
public R<?> resetPassword(@RequestParam("userId") Long userId) {
SysUserBase user = sysUserBaseService.getById(userId);
if (ObjectUtil.isNull(user) || NumberUtil.isNullOrZero(user.getId())) {
return new R<>().error("未找到用户信息!");
}
SysUserBase update = new SysUserBase();
update.setId(userId);
update.setPasswd(ENCODER.encode(Constant.DEFAULT_PASSWORD));
update.setLastPwdTime(DateUtil.date());
sysUserBaseService.updateById(update);
sysUserBaseService.initRedisByUserName(user.getUserName());
return new R<>().success("");
}
/** /**
* 通过id删除系统基础用户表 * 通过id删除系统基础用户表
* *
* @return R * @return R
*/ */
@SysLog
@ApiOperation("删除系统基础用户表") @ApiOperation("删除系统基础用户表")
@DeleteMapping("/{userId}") @DeleteMapping("/{userId}")
@PreAuthorize("@pms.hasPermission('ROLE_admin')")
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
public R removeById(@PathVariable Long userId) { public R removeById(@PathVariable Long userId) {
hpUserRoleService.removeByUserId(userId); hpUserRoleService.removeByUserId(userId);
......
package cn.sh.stc.sict.cloud.upms.controller.web;
import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import cn.sh.stc.sict.cloud.upms.service.SysWxLogService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 系统日志
*
* @author F_xh。
* @date 2020-12-27 11:34:55
*/
@RestController
@RequestMapping("/wx/syslog")
@AllArgsConstructor
@Slf4j
@Api(tags = "C端系统日志")
public class SysWxLogController {
private SysWxLogService sysWxLogService;
/**
* 分页查询
*
* @param page 分页对象
* @return
*/
@ApiOperation("分页查询 系统日志")
@GetMapping("/page")
public R getSysLogPage(Page page, SysWxLog sysWxLog) {
LambdaQueryWrapper<SysWxLog> wrapper = Wrappers.lambdaQuery();
wrapper.like(StrUtil.isNotBlank(sysWxLog.getTitle()), SysWxLog::getTitle, sysWxLog.getTitle())
.like(StrUtil.isNotBlank(sysWxLog.getMethod()), SysWxLog::getMethod, sysWxLog.getMethod())
.like(StrUtil.isNotBlank(sysWxLog.getParams()), SysWxLog::getParams, sysWxLog.getParams())
.orderByDesc(SysWxLog::getCreateTime);
return new R<>(sysWxLogService.page(page, wrapper));
}
/**
* 通过id查询系统日志
*
* @param id id
* @return R
*/
@ApiOperation("通过id查询 系统日志")
@GetMapping("/{id}")
public R getById(@PathVariable("id") Long id) {
return new R<>(sysWxLogService.getById(id));
}
/**
* 新增系统日志
* @param sysLog 系统日志
* @return R
*/
// @ApiOperation("新增系统日志")
// @PostMapping
// public R save(@RequestBody SysLog sysLog){
// return new R<>(sysLogService.save(sysLog));
// }
/**
* 修改系统日志
* @param sysLog 系统日志
* @return R
*/
// @ApiOperation("修改系统日志")
// @PutMapping
// public R updateById(@RequestBody SysLog sysLog){
// return new R<>(sysLogService.updateById(sysLog));
// }
/**
* 通过id删除系统日志
* @param id id
* @return R
*/
// @ApiOperation("删除系统日志")
// @DeleteMapping("/{id}")
// public R removeById(@PathVariable Long id){
// return new R<>(sysLogService.removeById(id));
// }
}
package cn.sh.stc.sict.cloud.upms.dao;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
/**
* 系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
@Mapper
public interface SysWxLogMapper extends BaseMapper<SysWxLog> {
}
package cn.sh.stc.sict.cloud.upms.dto;
import lombok.Data;
/**
* @author 75
* @Description
* @Date 2021/5/17 11:00
**/
@Data
public class ChangePasswordDTO {
private Long userId;
private String oldPassword;
private String newPassword;
}
package cn.sh.stc.sict.cloud.upms.model;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.Date;
/**
* C端-系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("sys_wx_log")
public class SysWxLog extends Model<SysWxLog> {
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId
@ApiModelProperty(hidden = false, value = "")
private Long id;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private Byte type;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String title;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String serviceId;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String remoteAddr;
/**
*
*/
@ApiModelProperty(hidden = false, value = "")
private String createBy;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(hidden = true, value = "")
private Long createUserId;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String userAgent;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String requestUri;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String method;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String params;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private Long time;
/**
*
*/
@ApiModelProperty(hidden = true, value = "")
private String exception;
/**
*
*/
@TableField(fill = FieldFill.INSERT)
@ApiModelProperty(hidden = true, value = "")
private Date createTime;
/**
* 主键值
*/
@Override
protected Serializable pkVal() {
return this.id;
}
}
...@@ -18,5 +18,9 @@ public interface SysUserBaseService extends IService<SysUserBase> { ...@@ -18,5 +18,9 @@ public interface SysUserBaseService extends IService<SysUserBase> {
UserInfo getUserInfoBySocial(String appId, String inStr) throws WxErrorException; UserInfo getUserInfoBySocial(String appId, String inStr) throws WxErrorException;
boolean saveDto(UserDTO dto); boolean saveDto(UserDTO dto);
boolean exist(SysUserBase user);
void initRedisByUserName(String userName);
} }
package cn.sh.stc.sict.cloud.upms.service;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import com.baomidou.mybatisplus.extension.service.IService;
/**
* 系统日志
*
* @author F_xh
* @date 2020-12-27 11:34:55
*/
public interface SysWxLogService extends IService<SysWxLog> {
}
package cn.sh.stc.sict.cloud.upms.service.impl;
import cn.sh.stc.sict.cloud.upms.dao.SysWxLogMapper;
import cn.sh.stc.sict.cloud.upms.model.SysWxLog;
import cn.sh.stc.sict.cloud.upms.service.SysWxLogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@Service("sysWxLogService")
@AllArgsConstructor
public class SysWxLogServiceImpl extends ServiceImpl<SysWxLogMapper, SysWxLog> implements SysWxLogService {
private final SysWxLogMapper sysWxLogMapper;
}
...@@ -11,9 +11,9 @@ spring: ...@@ -11,9 +11,9 @@ spring:
nacos: nacos:
server-addr: 127.0.0.1:8848 server-addr: 127.0.0.1:8848
discovery: discovery:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
config: config:
namespace: bbe7ca0d-f409-4e68-bf95-5f2adad168e7 namespace: be9383c3-e535-4e9c-81ab-a8c6b7ecdc82
file-extension: yml file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles: profiles:
......
server:
port: 12256
spring:
application:
name: @artifactId@
main:
allow-bean-definition-overriding: true
# nacos
cloud:
nacos:
server-addr: 127.0.0.1:8848
discovery:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
config:
namespace: eb001e6c-9c22-421f-8f36-ed92821014d8
file-extension: yml
shared-dataids: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
profiles:
active: dev
...@@ -16,7 +16,10 @@ ...@@ -16,7 +16,10 @@
<groupId>cn.sh.stc.sict</groupId> <groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-data</artifactId> <artifactId>cloud-common-data</artifactId>
</dependency> </dependency>
<dependency>
<groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-log</artifactId>
</dependency>
<dependency> <dependency>
<groupId>cn.sh.stc.sict</groupId> <groupId>cn.sh.stc.sict</groupId>
<artifactId>cloud-common-minio</artifactId> <artifactId>cloud-common-minio</artifactId>
...@@ -32,6 +35,15 @@ ...@@ -32,6 +35,15 @@
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId> <artifactId>spring-boot-starter-web</artifactId>
</dependency> </dependency>
<dependency>
<groupId>org.java-websocket</groupId>
<artifactId>Java-WebSocket</artifactId>
<version>1.3.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
<!--undertow容器--> <!--undertow容器-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
......
...@@ -4,13 +4,17 @@ import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients; ...@@ -4,13 +4,17 @@ import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictFeignClients;
import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictResourceServer; import cn.sh.stc.sict.cloud.common.security.annotation.EnableSictResourceServer;
import cn.sh.stc.sict.cloud.common.swagger.annotation.EnableSictSwagger2; import cn.sh.stc.sict.cloud.common.swagger.annotation.EnableSictSwagger2;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.cloud.client.SpringCloudApplication; import org.springframework.cloud.client.SpringCloudApplication;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
/** /**
* @author F_xh * @author F_xh
*/ */
@EnableAsync
@EnableCaching
@EnableScheduling @EnableScheduling
@EnableSictSwagger2 @EnableSictSwagger2
@SpringCloudApplication @SpringCloudApplication
......
package cn.sh.stc.sict.theme.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author gao
* @date 2023/05/30 13:50
*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface SecurityParameter {
/**
* 入参是否解密,默认解密
*/
boolean inDecode() default true;
/**
* 出参是否加密,默认加密
*/
boolean outEncode() default true;
}
package cn.sh.stc.sict.theme.common.crypto;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 13:49
*/
@Data
public class EncryptionRequest {
/**
* rsa加密后的aes秘钥
*/
private String encryptionKey;
/**
*aes加密后的数据内容
*/
private String encryptionData;
}
package cn.sh.stc.sict.theme.common.crypto;
/**
* @author gao
* @date 2023/05/30 13:59
*/
public class EncryptionResponse {
}
package cn.sh.stc.sict.theme.common.crypto;
import cn.hutool.core.io.IoUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.RSA;
import cn.hutool.crypto.symmetric.AES;
import cn.sh.stc.sict.cloud.common.core.util.CryptUtil;
import java.io.InputStream;
/**
* @author gao
* @date 2023/05/30 13:48
*/
public class EncryptionUtil {
private static final String SIGN_TYPE_RSA = "RSA";
private static final int DEFAULT_RSA_KEY_SIZE = 1024;
private static final String DEFAULT_AES_KEY = "1qaz@WSX3edc$RFV";
public static final String PRIVATE_KEY = "MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAjQnqX7O3S6eDLzw4tw9K2IsWUuS9WCptg32AmaNMN+1YawmqDVOtrnkOyECZleuir62Y6ptw8yN0cyYzMFezDQIDAQABAkB9c5Jr6flia+/+Nfzkp8+VabJDrX7WS3b5/MpE3sHPBBQ/9HhAyg7k/MHTFZ8wScziFLPQ/wb6+szacNvA1RrpAiEA2Ei7JY6L/dv9hQ+YKYblCeGIQG8FUi4Uy7xheg1M/ZMCIQCm7/xBJCMubyyKHgRXr6MonqPdu2IE51IqmerXQV/w3wIgZ9jMGuVNrC8zk+7/5XiCgnMKg72KtYGwtH4X4419WQcCIExumHpix1DdSfE66RYUrolMiQ5eWvSPzMkAi8tefUTVAiB6F4fXbtKbqpJxW5dQttJl0RsEB39HGgOjy4mLaYZgvg==";
public static final String PUBLIC_KEY = "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAI0J6l+zt0ungy88OLcPStiLFlLkvVgqbYN9gJmjTDftWGsJqg1Tra55DshAmZXroq+tmOqbcPMjdHMmMzBXsw0CAwEAAQ==";
// 创建rsa加密对象 服务端公钥是不需要的,公钥提供给前端就行
private final static cn.hutool.crypto.asymmetric.RSA RSA = new RSA(PRIVATE_KEY, PUBLIC_KEY);
/**
* 获取加密返回
*/
public static String getEncodeResponse(String encryptionData) {
// return Base64.encode(encryptionData);
return CryptUtil.toAES(encryptionData, DEFAULT_AES_KEY);
}
/**
* 获取解密返回流
*/
public static InputStream getDecodeInputStream(EncryptionRequest request) {
String encryptionKey = request.getEncryptionKey();
// rsa解密 获取aes秘钥
byte[] decryptKey = RSA.decrypt(encryptionKey, KeyType.PrivateKey);
// aes进行解密内容 获取输入流(方便整合springMVC)
AES aes = SecureUtil.aes(decryptKey);
byte[] decryptData = aes.decrypt(request.getEncryptionData());
return IoUtil.toStream(decryptData);
}
// public static void main(String[] args) {
// KeyPair kp = SecureUtil.generateKeyPair(SIGN_TYPE_RSA, DEFAULT_RSA_KEY_SIZE);
// PublicKey pbkey = kp.getPublic();
// PrivateKey prkey = kp.getPrivate();
// String pubkey = (new BASE64Encoder()).encode(pbkey.getEncoded());
// String prikey = (new BASE64Encoder()).encode(prkey.getEncoded());
// //logger.info("{}生成秘钥成功,公钥:{},私钥:{}",appkey,pubkey,prikey);
// Map map = new HashMap();
// map.put("pub", pubkey);
// map.put("pri", prikey);
//
// }
}
package cn.sh.stc.sict.theme.common.rsa;
import lombok.Data;
/**
* @author gao
* @date 2023/05/30 11:16
*/
@Data
public class RSADecodeData {
/**
* Aes密钥
*/
private String key;
/**
* 偏移量
*/
private String keyVI;
/**
* 时间
*/
private String time;
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.common.crypto.EncryptionRequest;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.RequestBodyAdvice;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Type;
/**
* @author gao
* @date 2023/05/30 13:55
*/
@Slf4j
@ControllerAdvice
@RequiredArgsConstructor
public class DecodeRequestAdvice implements RequestBodyAdvice {
private final ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
// 判断方法是否需要进行解密
return true;
}
@Override
public HttpInputMessage beforeBodyRead(HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) throws IOException {
// 读取body对象,获取EncryptionRequest对象
InputStream body = httpInputMessage.getBody();
EncryptionRequest encryptionRequest = objectMapper.readValue(body, EncryptionRequest.class);
if (encryptionRequest.getEncryptionKey() == null) {
throw new IllegalArgumentException("encryption error,request is null");
}
// 转换成解密后的HttpInputMessage对象
return new HttpInputMessage() {
@Override
public HttpHeaders getHeaders() {
return httpInputMessage.getHeaders();
}
// 解密后的输入流
@Override
public InputStream getBody() {
return EncryptionUtil.getDecodeInputStream(encryptionRequest);
}
};
}
@Override
public Object afterBodyRead(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
@Override
public Object handleEmptyBody(Object o, HttpInputMessage httpInputMessage, MethodParameter methodParameter, Type type, Class<? extends HttpMessageConverter<?>> aClass) {
return o;
}
}
package cn.sh.stc.sict.theme.config;
import cn.sh.stc.sict.theme.annotation.SecurityParameter;
import cn.sh.stc.sict.theme.common.crypto.EncryptionUtil;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
/**
* @author gao
* @date 2023/05/30 13:52
*/
@Slf4j
@ControllerAdvice
public class EncodeResponseAdvice implements ResponseBodyAdvice {
@Autowired
private ObjectMapper objectMapper;
@Override
public boolean supports(MethodParameter methodParameter, Class aClass) {
// 方法上有SecurityParameter注解的进行加密 根据需求可以在判断SecurityParameter注解中的outEncode是否为true
// 这里返回true对所有接口返回结果加密,可能影响swagger显示
return true;
}
@Override
public Object beforeBodyWrite(Object o,
MethodParameter methodParameter,
MediaType mediaType,
Class aClass,
ServerHttpRequest serverHttpRequest,
ServerHttpResponse serverHttpResponse) {
try {
// 要支持接口返回string的话,response需要序列化成string对象,因为接口返回string和对象使用消息转换器不是一样的
// 把返回结果序列化成json
String dataJson = objectMapper.writeValueAsString(o);
// 进行加密返回
return EncryptionUtil.getEncodeResponse(dataJson);
} catch (JsonProcessingException e) {
log.error("json processing error", e);
}
return o;
}
}
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.log.annotation.SysLog;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.model.HpAppointmentEva;
import cn.sh.stc.sict.theme.hpgp.service.HpAppointmentEvaService;
import cn.sh.stc.sict.theme.hphy.model.HpAppointment;
import cn.sh.stc.sict.theme.hphy.service.HpAppointmentService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import java.util.Date;
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]预约评价")
@RequestMapping("/hp/app/eva")
public class HpAppointmentEvaController {
/**
* 1. 已评价 page
* 2. 待评价 page
* 3. 评价
*/
private final HpAppointmentService hpAppointmentService;
private final HpAppointmentEvaService hpAppointmentEvaService;
@ApiOperation("已评价 分页")
@GetMapping("/eaved/page")
public R hasEavedPage(Page page, @RequestParam("patientId") Long patientId) {
LambdaQueryWrapper<HpAppointmentEva> wrapper = Wrappers.lambdaQuery();
wrapper.eq(HpAppointmentEva::getPatientId, patientId);
return new R(hpAppointmentEvaService.page(page, wrapper));
}
@ApiOperation("待评价 分页")
@GetMapping("/todo/eav/page")
public R toBeEavPage(Page page, @RequestParam("patientId") Long patientId) {
page = hpAppointmentEvaService.toBeEavPage(page, patientId);
return new R(page);
}
@SysLog
@ApiOperation("评价")
@PostMapping("/eva")
@Transactional(rollbackFor = Exception.class)
public R eav(@RequestBody HpAppointmentEva eva) {
if(NumberUtil.isNullOrZero(eva.getAppId())){
return new R().error("appId 不可为空!");
}
if(NumberUtil.isNullOrZero(eva.getPatientId())){
return new R().error("patientId 不可为空!");
}
HpAppointment app = hpAppointmentService.getById(eva.getAppId());
if(ObjectUtil.isNull(app)){
return new R().error("未找到预约记录!");
}
if(!Constant.BYTE_NO.equals(app.getEvaStatus())){
return new R().error("该预约记录已评价!");
}
CurrentUser current = SecurityUtils.getCurrentUser();
eva.setUserId(current.getId());
eva.setPatientName(app.getPatientName());
eva.setHospCode(app.getHosOrgCode());
eva.setHospName(app.getHosOrgName());
eva.setDeptCode(app.getDeptCode());
eva.setDeptName(app.getDeptName());
eva.setDoctorCode(app.getDoctorId());
eva.setDoctorName(app.getDoctorName());
eva.setCreateTime(DateUtil.date());
hpAppointmentEvaService.save(eva);
HpAppointment update = new HpAppointment();
update.setId(eva.getAppId());
update.setEvaStatus(Constant.BYTE_YES);
hpAppointmentService.updateById(update);
return new R();
}
}
\ No newline at end of file
package cn.sh.stc.sict.theme.hpgp.controller.mobile;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.util.SecurityUtils;
import cn.sh.stc.sict.cloud.upms.dto.CurrentUser;
import cn.sh.stc.sict.theme.hpgp.model.HpgpBusyIdlePrediction;
import cn.sh.stc.sict.theme.hpgp.service.HpHzjlService;
import cn.sh.stc.sict.theme.hphy.model.HpDocInfo;
import cn.sh.stc.sict.theme.hphy.model.HphyPatientBase;
import cn.sh.stc.sict.theme.hphy.service.HphyPatientBaseService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
/**
* (HpHzjl)表控制层
*
* @author F_xh
* @since 2022-08-15 14:14:33
*/
@Slf4j
@RestController
@AllArgsConstructor
@Api(tags = "[C]患者就诊记录")
@RequestMapping("/hpHzjl")
public class HpHzjlController {
/**
* 服务对象
*/
private final HpHzjlService hpHzjlService;
private final HphyPatientBaseService hphyPatientBaseService;
@ApiOperation("历史科室 list")
@GetMapping("/history/dept/list")
public R historyDeptList() {
CurrentUser current = SecurityUtils.getCurrentUser();
if (ObjectUtil.isEmpty(current) || StrUtil.isBlank(current.getOpenId())) {
log.error("current = {}", JSONUtil.toJsonStr(current));
return new R().error("当前的登录人信息异常");
}
HphyPatientBase patient = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (ObjectUtil.isEmpty(patient) || StrUtil.isBlank(patient.getCertId())) {
log.error("patient = {}", JSONUtil.toJsonStr(patient));
return new R().error("患者信息异常!");
}
List<HpgpBusyIdlePrediction> result = hpHzjlService.listByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode());
return new R(result);
}
@ApiOperation("历史医生 list")
@GetMapping("/history/doctor/list")
public R historyDoctorList() {
CurrentUser current = SecurityUtils.getCurrentUser();
if (ObjectUtil.isEmpty(current) || StrUtil.isBlank(current.getOpenId())) {
log.error("current = {}", JSONUtil.toJsonStr(current));
return new R().error("当前的登录人信息异常");
}
HphyPatientBase patient = hphyPatientBaseService.getByOpenId(current.getOpenId());
if (ObjectUtil.isEmpty(patient) || StrUtil.isBlank(patient.getCertId())) {
log.error("patient = {}", JSONUtil.toJsonStr(patient));
return new R().error("患者信息异常!");
}
List<HpDocInfo> result = hpHzjlService.listDoctorByCertIdAndHosCode(patient.getCertId(), current.getHospitalCode());
return new R(result);
}
}