diff --git a/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java b/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java index ce91df56..27c21e0e 100644 --- a/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java +++ b/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java @@ -1,5 +1,6 @@ package com.acupuncture; +import org.mybatis.spring.annotation.MapperScan; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; @@ -9,6 +10,7 @@ import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration; * * @author acupuncture */ +@MapperScan({"com.acupuncture.**.mapper", "com.acupuncture.**.dao"}) @SpringBootApplication(exclude = { DataSourceAutoConfiguration.class }) public class AcupunctureApplication { diff --git a/acupuncture-admin/src/main/java/com/acupuncture/web/controller/web/DmsLoginController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/web/DmsLoginController.java new file mode 100644 index 00000000..4ff0da1c --- /dev/null +++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/web/DmsLoginController.java @@ -0,0 +1,87 @@ +package com.acupuncture.web.controller.web; + +import com.acupuncture.common.constant.Constants; +import com.acupuncture.common.core.domain.AjaxResult; +import com.acupuncture.common.core.domain.entity.SysUser; +import com.acupuncture.common.core.domain.model.LoginBody; +import com.acupuncture.common.core.domain.model.LoginUser; +import com.acupuncture.common.utils.SecurityUtils; +import com.acupuncture.framework.web.service.SysPermissionService; +import com.acupuncture.framework.web.service.TokenService; +import com.acupuncture.framework.web.service.WebDmsLoginService; +import io.swagger.annotations.Api; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.web.bind.annotation.*; + +import javax.annotation.Resource; +import java.util.Set; + +/** + * @Author zzc + * @Package com.acupuncture.web.controller.web + * @Date 2025/2/10 10:44 + * @description: + */ +@Slf4j +@Api(tags = "填报端登录") +@RestController +@RequestMapping("/web") +public class DmsLoginController { + + @Resource + private WebDmsLoginService webDmsLoginService; + @Resource + private SysPermissionService permissionService; + + @Resource + private TokenService tokenService; + + + /** + * 登录方法 + * + * @param loginBody 登录信息 + * @return 结果 + */ + @PostMapping("/login") + public AjaxResult login(@RequestBody LoginBody loginBody) + { + AjaxResult ajax = AjaxResult.success(); + // 生成令牌 + String token = webDmsLoginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), + loginBody.getUuid()); + ajax.put(Constants.TOKEN, token); + return ajax; + } + + /** + * 获取用户信息 + * + * @return 用户信息 + */ + @GetMapping("getInfo") + public AjaxResult getInfo() + { + LoginUser loginUser = SecurityUtils.getLoginUser(); + SysUser user = loginUser.getUser(); + // 角色集合 + Set roles = permissionService.getRolePermission(user); + // 权限集合 + Set permissions = permissionService.getMenuPermission(user); + if (!loginUser.getPermissions().equals(permissions)) + { + loginUser.setPermissions(permissions); + tokenService.refreshToken(loginUser); + } + AjaxResult ajax = AjaxResult.success(); + ajax.put("user", user); + ajax.put("roles", roles); + ajax.put("permissions", permissions); + ajax.put("tenantId", loginUser.getTenantId()); + ajax.put("scoreId", loginUser.getScoreId()); + + return ajax; + } + +} diff --git a/acupuncture-admin/src/main/resources/application-dev.yml b/acupuncture-admin/src/main/resources/application-dev.yml index b9ac721a..a6042094 100644 --- a/acupuncture-admin/src/main/resources/application-dev.yml +++ b/acupuncture-admin/src/main/resources/application-dev.yml @@ -12,10 +12,10 @@ spring: # 从库数据源 slave: # 从数据源开关/默认关闭 - enabled: false - url: - username: - password: + enabled: true + url: jdbc:mysql://localhost:3306/acupuncture_yfyy?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8 + username: root + password: q7510327 # 初始连接数 initialSize: 5 # 最小连接池数量 diff --git a/acupuncture-admin/src/main/resources/application.yml b/acupuncture-admin/src/main/resources/application.yml index 407a9b58..119a9df6 100644 --- a/acupuncture-admin/src/main/resources/application.yml +++ b/acupuncture-admin/src/main/resources/application.yml @@ -16,7 +16,7 @@ acupuncture: # 开发环境配置 server: # 服务器的HTTP端口,默认为8080 - port: 8080 + port: 20001 servlet: # 应用的访问路径 context-path: / @@ -102,7 +102,7 @@ mybatis: # 搜索指定包别名 typeAliasesPackage: com.acupuncture.**.domain # 配置mapper的扫描,找到所有的mapper.xml映射文件 - mapperLocations: classpath*:mapper/**/*Mapper.xml + mapperLocations: classpath*:mapper/**/*Mapper.xml,classpath*:mapper/**/*Dao.xml # 加载全局的配置文件 configLocation: classpath:mybatis/mybatis-config.xml diff --git a/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java index 35600b6e..52dc8f7d 100644 --- a/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java +++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java @@ -89,6 +89,10 @@ public class SysUser extends BaseEntity /** 角色ID */ private Long roleId; + private Long tenantId; + + private Long scoreId; + public SysUser() { @@ -297,6 +301,22 @@ public class SysUser extends BaseEntity this.roleId = roleId; } + public Long getTenantId() { + return tenantId; + } + + public void setTenantId(Long tenantId) { + this.tenantId = tenantId; + } + + public Long getScoreId() { + return scoreId; + } + + public void setScoreId(Long scoreId) { + this.scoreId = scoreId; + } + @Override public String toString() { return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE) diff --git a/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java index 9942e695..c32de541 100644 --- a/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java +++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java @@ -71,6 +71,10 @@ public class LoginUser implements UserDetails */ private SysUser user; + private Long tenantId; + + private Long scoreId; + public LoginUser() { } @@ -89,6 +93,15 @@ public class LoginUser implements UserDetails this.permissions = permissions; } + public LoginUser(Long userId, Long deptId, SysUser user, Set permissions, Long tenantId, Long scoreId) + { + this.userId = userId; + this.deptId = deptId; + this.user = user; + this.permissions = permissions; + this.tenantId = tenantId; + this.scoreId = scoreId; + } public Long getUserId() { return userId; @@ -258,6 +271,22 @@ public class LoginUser implements UserDetails this.user = user; } + public Long getTenantId() { + return tenantId; + } + + public void setTenantId(Long tenantId) { + this.tenantId = tenantId; + } + + public Long getScoreId() { + return scoreId; + } + + public void setScoreId(Long scoreId) { + this.scoreId = scoreId; + } + @Override public Collection getAuthorities() { diff --git a/acupuncture-framework/pom.xml b/acupuncture-framework/pom.xml index 1295e36d..1a047376 100644 --- a/acupuncture-framework/pom.xml +++ b/acupuncture-framework/pom.xml @@ -59,6 +59,11 @@ acupuncture-system + + cn.hutool + hutool-all + 5.8.24 + \ No newline at end of file diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java index 6f45c4b0..ec943aa2 100644 --- a/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java @@ -1,5 +1,6 @@ package com.acupuncture.framework.config; +import com.acupuncture.framework.security.provider.DmsUserAuthenticationProvider; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -7,8 +8,10 @@ import org.springframework.http.HttpMethod; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.ProviderManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; +import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @@ -75,7 +78,7 @@ public class SecurityConfig DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setUserDetailsService(userDetailsService); daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder()); - return new ProviderManager(daoAuthenticationProvider); + return new ProviderManager(daoAuthenticationProvider, dmsUserAuthenticationProvider()); } /** @@ -111,7 +114,7 @@ public class SecurityConfig .authorizeHttpRequests((requests) -> { permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll()); // 对于登录login 注册register 验证码captchaImage 允许匿名访问 - requests.antMatchers("/login", "/register", "/captchaImage").permitAll() + requests.antMatchers("/login", "/register", "/captchaImage", "/web/login").permitAll() // 静态资源,可匿名访问 .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll() .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll() @@ -136,4 +139,25 @@ public class SecurityConfig { return new BCryptPasswordEncoder(); } + + @Bean + public DmsUserAuthenticationProvider dmsUserAuthenticationProvider(){ + return new DmsUserAuthenticationProvider(); + } + +// @Override +// protected void configure(AuthenticationManagerBuilder auth) throws Exception { +// //填报端认证 +// auth.authenticationProvider(dmsUserAuthenticationProvider()); +// //用户名密码认证 +// auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder()); +// } + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http + // ... 其他配置 + .authenticationProvider(dmsUserAuthenticationProvider()); // 注入自定义 Provider + return http.build(); + } } diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/security/provider/DmsUserAuthenticationProvider.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/provider/DmsUserAuthenticationProvider.java new file mode 100644 index 00000000..23f95e06 --- /dev/null +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/provider/DmsUserAuthenticationProvider.java @@ -0,0 +1,45 @@ +package com.acupuncture.framework.security.provider; + +import com.acupuncture.framework.security.token.DmsUserAuthenticationToken; +import com.acupuncture.framework.web.service.UserDetailsServiceImpl; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.core.userdetails.UserDetails; + +import javax.annotation.Resource; +import java.util.Collections; + +/** + * @Author zzc + * @Package com.acupuncture.framework.security.provider + * @Date 2025/2/10 9:41 + * @description: + */ +public class DmsUserAuthenticationProvider implements AuthenticationProvider { + /** + * 用户输入用户名密码,匹配主库dms_user租户用户表,根据dms_user表中tenant_id租户ID字段匹配dms_tenant租户表中的id, + * 如租户用户正常,且租户正常、数据源正常,则创建返回token,token中存用户信息、组织信息、数据源信息; 数据源找不到或错误,则异常 + */ + + @Resource + private UserDetailsServiceImpl userDetailsService; + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + String username = (String) authentication.getPrincipal(); + String password = (String) authentication.getCredentials(); + //通过openId获取用户 + UserDetails userDetails = userDetailsService.loadDmsUserByUsername(username); + //返回用户信息 + DmsUserAuthenticationToken result = new DmsUserAuthenticationToken(userDetails, Collections.emptyList()); + result.setDetails(authentication.getDetails()); + return result; + } + + @Override + public boolean supports(Class authentication) { + return (DmsUserAuthenticationToken.class.isAssignableFrom(authentication)); + } +} diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/security/token/DmsUserAuthenticationToken.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/token/DmsUserAuthenticationToken.java new file mode 100644 index 00000000..6c39a01d --- /dev/null +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/token/DmsUserAuthenticationToken.java @@ -0,0 +1,71 @@ +package com.acupuncture.framework.security.token; + +import org.springframework.security.authentication.AbstractAuthenticationToken; +import org.springframework.security.core.GrantedAuthority; +import org.springframework.security.core.SpringSecurityCoreVersion; + +import java.util.Collection; + +/** + * @author zhangsan + * @date 2022-08-11 21:15 + * @description TODO + */ +public class DmsUserAuthenticationToken extends AbstractAuthenticationToken { + private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; + + private final Object principal; + private String credentials; + + /** + * 准备登录时调用 + * 此构造函数用来初始化未授信凭据. + * + * @param principal + * @param credentials + */ + public DmsUserAuthenticationToken(Object principal, String credentials) { + super(null); + this.principal = principal; + this.credentials = credentials; + setAuthenticated(false); + } + + /** + * 登录成功时调用 + * 此构函数用来初始化已授信凭据. + * @param principal + * @param authorities + */ + public DmsUserAuthenticationToken(Object principal, Collection authorities) { + super(authorities); + this.principal = principal; + this.credentials = null; + super.setAuthenticated(true); + } + + @Override + public Object getPrincipal() { + return principal; + } + + @Override + public Object getCredentials() { + return credentials; + } + + @Override + public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException { + if (isAuthenticated) { + throw new IllegalArgumentException( + "Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead"); + } + super.setAuthenticated(false); + } + + @Override + public void eraseCredentials() { + super.eraseCredentials(); + credentials = null; + } +} \ No newline at end of file diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java index 9cb4d385..8efafe15 100644 --- a/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java @@ -100,6 +100,54 @@ public class SysLoginService return tokenService.createToken(loginUser); } + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String dmsLogin(String username, String password, String code, String uuid) + { + // 验证码校验 + validateCaptcha(username, code, uuid); + // 登录前置校验 + loginPreCheck(username, password); + // 用户验证 + Authentication authentication = null; + try + { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); + AuthenticationContextHolder.setContext(authenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) + { + if (e instanceof BadCredentialsException) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } + finally + { + AuthenticationContextHolder.clearContext(); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + // 生成token + return tokenService.createToken(loginUser); + } + /** * 校验验证码 * diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java index 6d1ab302..5a41ad57 100644 --- a/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java @@ -1,5 +1,8 @@ package com.acupuncture.framework.web.service; +import cn.hutool.core.collection.CollUtil; +import com.acupuncture.system.domain.vo.DmsLoginUserVo; +import com.acupuncture.system.service.DmsLoginService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -14,6 +17,7 @@ import com.acupuncture.common.exception.ServiceException; import com.acupuncture.common.utils.MessageUtils; import com.acupuncture.common.utils.StringUtils; import com.acupuncture.system.service.ISysUserService; +import javax.annotation.Resource; /** * 用户验证处理 @@ -34,6 +38,9 @@ public class UserDetailsServiceImpl implements UserDetailsService @Autowired private SysPermissionService permissionService; + @Resource + private DmsLoginService dmsLoginService; + @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { @@ -59,8 +66,41 @@ public class UserDetailsServiceImpl implements UserDetailsService return createLoginUser(user); } + + public UserDetails loadDmsUserByUsername(String username) throws UsernameNotFoundException + { + DmsLoginUserVo.DataScoreVo dataScoreVo = dmsLoginService.selectUserByUserName(username); + if (StringUtils.isNull(dataScoreVo)) + { + log.info("登录用户:{} 不存在.", username); + throw new ServiceException(MessageUtils.message("user.not.exists")); + } + else if (UserStatus.DELETED.getCode().equals(dataScoreVo.getDelFlag())) + { + log.info("登录用户:{} 已被删除.", username); + throw new ServiceException(MessageUtils.message("user.password.delete")); + } + else if (UserStatus.DISABLE.getCode().equals(dataScoreVo.getStatus())) + { + log.info("登录用户:{} 已被停用.", username); + throw new ServiceException(MessageUtils.message("user.blocked")); + } + +// passwordService.validate(user); + + return createLoginUser(dataScoreVo); + } + public UserDetails createLoginUser(SysUser user) { return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user)); } + + public UserDetails createLoginUser(DmsLoginUserVo.DataScoreVo user) + { + SysUser sysUser = new SysUser(); + sysUser.setUserName(user.getDmsUsername()); + sysUser.setUserId(user.getDmsUserId()); + return new LoginUser(user.getDmsUserId(), user.getHospitalId(), sysUser, CollUtil.newHashSet(), user.getTenantId() ,user.getScoreId()); + } } diff --git a/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/WebDmsLoginService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/WebDmsLoginService.java new file mode 100644 index 00000000..9f65dacb --- /dev/null +++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/WebDmsLoginService.java @@ -0,0 +1,227 @@ +package com.acupuncture.framework.web.service; + +import com.acupuncture.common.constant.CacheConstants; +import com.acupuncture.common.constant.Constants; +import com.acupuncture.common.constant.UserConstants; +import com.acupuncture.common.core.domain.entity.SysUser; +import com.acupuncture.common.core.domain.model.LoginUser; +import com.acupuncture.common.core.redis.RedisCache; +import com.acupuncture.common.exception.ServiceException; +import com.acupuncture.common.exception.user.*; +import com.acupuncture.common.utils.DateUtils; +import com.acupuncture.common.utils.MessageUtils; +import com.acupuncture.common.utils.StringUtils; +import com.acupuncture.common.utils.ip.IpUtils; +import com.acupuncture.framework.manager.AsyncManager; +import com.acupuncture.framework.manager.factory.AsyncFactory; +import com.acupuncture.framework.security.context.AuthenticationContextHolder; +import com.acupuncture.framework.security.token.DmsUserAuthenticationToken; +import com.acupuncture.system.service.ISysConfigService; +import com.acupuncture.system.service.ISysUserService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.stereotype.Component; + +import javax.annotation.Resource; + +/** + * 登录校验方法 + * + * @author acupuncture + */ +@Component +public class WebDmsLoginService +{ + @Autowired + private TokenService tokenService; + + @Resource + private AuthenticationManager authenticationManager; + + @Autowired + private RedisCache redisCache; + + @Autowired + private ISysUserService userService; + + @Autowired + private ISysConfigService configService; + + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String login(String username, String password, String code, String uuid) + { + // 验证码校验 +// validateCaptcha(username, code, uuid); + // 登录前置校验 + loginPreCheck(username, password); + // 用户验证 + Authentication authentication = null; + try + { + DmsUserAuthenticationToken authenticationToken = new DmsUserAuthenticationToken(username, password); + AuthenticationContextHolder.setContext(authenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) + { + if (e instanceof BadCredentialsException) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } + finally + { + AuthenticationContextHolder.clearContext(); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + // 生成token + return tokenService.createToken(loginUser); + } + + /** + * 登录验证 + * + * @param username 用户名 + * @param password 密码 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public String dmsLogin(String username, String password, String code, String uuid) + { + // 验证码校验 + validateCaptcha(username, code, uuid); + // 登录前置校验 + loginPreCheck(username, password); + // 用户验证 + Authentication authentication = null; + try + { + UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password); + AuthenticationContextHolder.setContext(authenticationToken); + // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername + authentication = authenticationManager.authenticate(authenticationToken); + } + catch (Exception e) + { + if (e instanceof BadCredentialsException) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + else + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage())); + throw new ServiceException(e.getMessage()); + } + } + finally + { + AuthenticationContextHolder.clearContext(); + } + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success"))); + LoginUser loginUser = (LoginUser) authentication.getPrincipal(); + recordLoginInfo(loginUser.getUserId()); + // 生成token + return tokenService.createToken(loginUser); + } + + /** + * 校验验证码 + * + * @param username 用户名 + * @param code 验证码 + * @param uuid 唯一标识 + * @return 结果 + */ + public void validateCaptcha(String username, String code, String uuid) + { + boolean captchaEnabled = configService.selectCaptchaEnabled(); + if (captchaEnabled) + { + String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, ""); + String captcha = redisCache.getCacheObject(verifyKey); + if (captcha == null) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"))); + throw new CaptchaExpireException(); + } + redisCache.deleteObject(verifyKey); + if (!code.equalsIgnoreCase(captcha)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"))); + throw new CaptchaException(); + } + } + } + + /** + * 登录前置校验 + * @param username 用户名 + * @param password 用户密码 + */ + public void loginPreCheck(String username, String password) + { + // 用户名或密码为空 错误 + if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null"))); + throw new UserNotExistsException(); + } + // 密码如果不在指定范围内 错误 + if (password.length() < UserConstants.PASSWORD_MIN_LENGTH + || password.length() > UserConstants.PASSWORD_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // 用户名不在指定范围内 错误 + if (username.length() < UserConstants.USERNAME_MIN_LENGTH + || username.length() > UserConstants.USERNAME_MAX_LENGTH) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match"))); + throw new UserPasswordNotMatchException(); + } + // IP黑名单校验 + String blackStr = configService.selectConfigByKey("sys.login.blackIPList"); + if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr())) + { + AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked"))); + throw new BlackListException(); + } + } + + /** + * 记录登录信息 + * + * @param userId 用户ID + */ + public void recordLoginInfo(Long userId) + { + SysUser sysUser = new SysUser(); + sysUser.setUserId(userId); + sysUser.setLoginIp(IpUtils.getIpAddr()); + sysUser.setLoginDate(DateUtils.getNowDate()); + userService.updateUserProfile(sysUser); + } +} diff --git a/acupuncture-system/pom.xml b/acupuncture-system/pom.xml index 1113f09b..601b0140 100644 --- a/acupuncture-system/pom.xml +++ b/acupuncture-system/pom.xml @@ -22,7 +22,21 @@ com.acupuncture acupuncture-common - + + org.projectlombok + lombok + + + cn.hutool + hutool-all + 5.8.24 + + + io.swagger + swagger-annotations + 1.6.2 + compile + \ No newline at end of file diff --git a/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/DmsLoginUserVo.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/DmsLoginUserVo.java new file mode 100644 index 00000000..58cc2599 --- /dev/null +++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/DmsLoginUserVo.java @@ -0,0 +1,76 @@ +package com.acupuncture.system.domain.vo; + +import com.acupuncture.system.domain.po.DmsUser; +import com.acupuncture.system.domain.po.UmsDataSource; +import io.swagger.annotations.ApiModelProperty; +import lombok.Data; + +import java.util.Date; + +/** + * @Author zzc + * @Package com.acupuncture.system.domain.vo + * @Date 2025/2/10 9:56 + * @description: + */ + +public class DmsLoginUserVo { + + @Data + public static class DmsUserVo { + private Integer id; + + private Long tenantId; + + private String userName; + + private String password; + + private String nickName; + + private String email; + + private String phonenumber; + + private String sex; + + private String status; + } + + @Data + public static class DataScoreVo { + + @ApiModelProperty("") + private Long tenantId; + @ApiModelProperty("") + private Long dmsUserId; + @ApiModelProperty("") + private String dmsUsername; + @ApiModelProperty("") + private String dmsUserNickName; + @ApiModelProperty("") + private Long scoreId; + @ApiModelProperty("") + private String dataSourceKey; + @ApiModelProperty("") + private Long hospitalId; + @ApiModelProperty("") + private String url; + @ApiModelProperty("") + private String username; + @ApiModelProperty("") + private String password; + @ApiModelProperty("") + private String createBy; + @ApiModelProperty("") + private Date createTime; + @ApiModelProperty("") + private String updateBy; + @ApiModelProperty("") + private Date updateTime; + @ApiModelProperty("") + private String delFlag; + @ApiModelProperty("") + private String status; + } +} diff --git a/acupuncture-system/src/main/java/com/acupuncture/system/persist/dao/DmsUserDao.java b/acupuncture-system/src/main/java/com/acupuncture/system/persist/dao/DmsUserDao.java new file mode 100644 index 00000000..755ab607 --- /dev/null +++ b/acupuncture-system/src/main/java/com/acupuncture/system/persist/dao/DmsUserDao.java @@ -0,0 +1,33 @@ +package com.acupuncture.system.persist.dao; + +import com.acupuncture.common.annotation.DataSource; +import com.acupuncture.common.enums.DataSourceType; +import com.acupuncture.system.domain.vo.DmsLoginUserVo; +import org.apache.ibatis.annotations.Param; + +/** + * @Author zzc + * @Package com.acupuncture.system.persist.dao + * @Date 2025/2/10 9:48 + * @description: + */ +public interface DmsUserDao { + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + @DataSource(DataSourceType.MASTER) + DmsLoginUserVo.DmsUserVo selectUserByUserName(@Param("userName") String userName); + + /** + * 根据用户名查询主库用户租户及数据源信息 + * @param userName + * @return + */ + @DataSource(DataSourceType.MASTER) + DmsLoginUserVo.DataScoreVo queryLoginUserDataScore(@Param("userName") String userName); + +} diff --git a/acupuncture-system/src/main/java/com/acupuncture/system/service/DmsLoginService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/DmsLoginService.java new file mode 100644 index 00000000..e379777a --- /dev/null +++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/DmsLoginService.java @@ -0,0 +1,22 @@ +package com.acupuncture.system.service; + +import com.acupuncture.common.core.domain.entity.SysUser; +import com.acupuncture.system.domain.po.DmsUser; +import com.acupuncture.system.domain.vo.DmsLoginUserVo; + +/** + * @Author zzc + * @Package com.acupuncture.system.service + * @Date 2025/2/10 9:29 + * @description: + */ +public interface DmsLoginService { + + /** + * 通过用户名查询用户 + * + * @param userName 用户名 + * @return 用户对象信息 + */ + public DmsLoginUserVo.DataScoreVo selectUserByUserName(String userName); +} diff --git a/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/DmsLoginServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/DmsLoginServiceImpl.java new file mode 100644 index 00000000..9123d325 --- /dev/null +++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/DmsLoginServiceImpl.java @@ -0,0 +1,27 @@ +package com.acupuncture.system.service.impl; + +import com.acupuncture.system.domain.po.DmsUser; +import com.acupuncture.system.domain.vo.DmsLoginUserVo; +import com.acupuncture.system.persist.dao.DmsUserDao; +import com.acupuncture.system.service.DmsLoginService; +import org.springframework.stereotype.Service; + +import javax.annotation.Resource; + +/** + * @Author zzc + * @Package com.acupuncture.system.service + * @Date 2025/2/10 9:29 + * @description: + */ +@Service +public class DmsLoginServiceImpl implements DmsLoginService { + + @Resource + private DmsUserDao dmsUserDao; + + @Override + public DmsLoginUserVo.DataScoreVo selectUserByUserName(String userName) { + return dmsUserDao.queryLoginUserDataScore(userName); + } +} diff --git a/acupuncture-system/src/main/resources/mapper/dao/SysPowerDao.xml b/acupuncture-system/src/main/resources/mapper/dao/SysPowerDao.xml new file mode 100644 index 00000000..b9a26dda --- /dev/null +++ b/acupuncture-system/src/main/resources/mapper/dao/SysPowerDao.xml @@ -0,0 +1,53 @@ + + + + + + + +