优化

master
smallbun 2024-12-16 01:06:32 +08:00
parent 9c135e74f3
commit 9be0add496
65 changed files with 533 additions and 251 deletions

View File

@ -36,7 +36,7 @@ import cn.topiam.employee.audit.entity.*;
import cn.topiam.employee.audit.enums.EventStatus; import cn.topiam.employee.audit.enums.EventStatus;
import cn.topiam.employee.audit.event.type.EventType; import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.support.context.ServletContextService; import cn.topiam.employee.support.context.ServletContextService;
import cn.topiam.employee.support.geo.GeoLocationService; import cn.topiam.employee.support.geo.GeoLocationParser;
import cn.topiam.employee.support.security.authentication.WebAuthenticationDetails; import cn.topiam.employee.support.security.authentication.WebAuthenticationDetails;
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.security.userdetails.UserType; import cn.topiam.employee.support.security.userdetails.UserType;
@ -272,7 +272,7 @@ public class AuditEventPublish {
private UserAgent getUserAgent() { private UserAgent getUserAgent() {
//@formatter:off //@formatter:off
HttpServletRequest request = ServletContextService.getRequest(); HttpServletRequest request = ServletContextService.getRequest();
cn.topiam.employee.support.web.useragent.UserAgent ua = UserAgentParser.getUserAgent(request); cn.topiam.employee.support.web.useragent.UserAgent ua = userAgentParser.getUserAgent(request);
return UserAgent.builder() return UserAgent.builder()
.browser(ua.getBrowser()) .browser(ua.getBrowser())
.browserType(ua.getBrowserType()) .browserType(ua.getBrowserType())
@ -293,7 +293,7 @@ public class AuditEventPublish {
//@formatter:off //@formatter:off
HttpServletRequest request = ServletContextService.getRequest(); HttpServletRequest request = ServletContextService.getRequest();
String ip = IpUtils.getIpAddr(request); String ip = IpUtils.getIpAddr(request);
cn.topiam.employee.support.geo.GeoLocation geoLocation = geoLocationService.getGeoLocation(ip); cn.topiam.employee.support.geo.GeoLocation geoLocation = geoLocationParser.getGeoLocation(ip);
if (Objects.isNull(geoLocation)){ if (Objects.isNull(geoLocation)){
return null; return null;
} }
@ -386,11 +386,17 @@ public class AuditEventPublish {
/** /**
* *
*/ */
private final GeoLocationService geoLocationService; private final GeoLocationParser geoLocationParser;
/**
* UserAgentParser
*/
private final UserAgentParser userAgentParser;
public AuditEventPublish(ApplicationEventPublisher applicationEventPublisher, public AuditEventPublish(ApplicationEventPublisher applicationEventPublisher,
GeoLocationService geoLocationService) { GeoLocationParser geoLocationParser, UserAgentParser userAgentParser) {
this.applicationEventPublisher = applicationEventPublisher; this.applicationEventPublisher = applicationEventPublisher;
this.geoLocationService = geoLocationService; this.geoLocationParser = geoLocationParser;
this.userAgentParser = userAgentParser;
} }
} }

View File

@ -18,11 +18,11 @@
package cn.topiam.employee.authentication.common.template; package cn.topiam.employee.authentication.common.template;
import java.io.IOException; import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap; import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.Map; import java.util.Map;
import org.apache.commons.compress.utils.CharsetNames;
import org.apache.http.entity.ContentType; import org.apache.http.entity.ContentType;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
@ -60,7 +60,7 @@ public class BindIdentityProviderTemplate {
ApiRestResult<Void> result) throws IOException { ApiRestResult<Void> result) throws IOException {
//@formatter:off //@formatter:off
try { try {
response.setCharacterEncoding(CharsetNames.UTF_8); response.setCharacterEncoding(StandardCharsets.UTF_8.name());
response.setContentType(ContentType.TEXT_HTML.getMimeType()); response.setContentType(ContentType.TEXT_HTML.getMimeType());
Template template = freemarkerTemplateConfiguration.getTemplate("bind_redirect.ftlh"); Template template = freemarkerTemplateConfiguration.getTemplate("bind_redirect.ftlh");
Map<String, Object> data = new HashMap<>(16); Map<String, Object> data = new HashMap<>(16);
@ -82,7 +82,7 @@ public class BindIdentityProviderTemplate {
freemarkerTemplateConfiguration freemarkerTemplateConfiguration
.setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/template/")); .setTemplateLoader(new ClassTemplateLoader(this.getClass(), "/template/"));
//编码 //编码
freemarkerTemplateConfiguration.setDefaultEncoding(CharsetNames.UTF_8); freemarkerTemplateConfiguration.setDefaultEncoding(StandardCharsets.UTF_8.name());
//国际化 //国际化
freemarkerTemplateConfiguration.setLocale(new Locale("zh_CN")); freemarkerTemplateConfiguration.setLocale(new Locale("zh_CN"));
} catch (Exception exception) { } catch (Exception exception) {

View File

@ -36,7 +36,7 @@ import cn.topiam.employee.common.repository.account.UserRepository;
import cn.topiam.employee.core.security.otp.OtpContextHelp; import cn.topiam.employee.core.security.otp.OtpContextHelp;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import jakarta.servlet.FilterChain; import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
@ -44,7 +44,7 @@ import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import static cn.topiam.employee.common.enums.MessageNoticeChannel.SMS; import static cn.topiam.employee.common.enums.MessageNoticeChannel.SMS;
import static cn.topiam.employee.support.security.constant.SecurityConstants.LOGIN_PATH; import static cn.topiam.employee.support.security.constant.SecurityConstants.LOGIN_PATH;
import static cn.topiam.employee.support.util.PhoneNumberUtils.isPhoneValidate; import static cn.topiam.employee.support.util.PhoneUtils.isPhoneValidate;
/** /**
* OTP * OTP
@ -85,7 +85,7 @@ public class SendSmsOtpFilter extends OncePerRequestFilter {
if (isPhoneValidate(recipient)) { if (isPhoneValidate(recipient)) {
//判断是否存在用户 //判断是否存在用户
Optional<UserEntity> user = userRepository Optional<UserEntity> user = userRepository
.findByPhone(PhoneNumberUtils.getPhoneNumber(recipient)); .findByPhone(PhoneUtils.getPhoneNumber(recipient));
if (user.isPresent()) { if (user.isPresent()) {
otpContextHelp.sendOtp(recipient, SmsType.LOGIN.getCode(), SMS); otpContextHelp.sendOtp(recipient, SmsType.LOGIN.getCode(), SMS);
HttpResponseUtils.flushResponseJson(response, HttpStatus.OK.value(), HttpResponseUtils.flushResponseJson(response, HttpStatus.OK.value(),

View File

@ -27,6 +27,7 @@ import org.springframework.security.core.AuthenticationException;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint; import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -71,4 +72,8 @@ public class ConsoleAuthenticationEntryPoint extends AbstractAuthenticationEntry
.build(); .build();
HttpResponseUtils.flushResponseJson(response, UNAUTHORIZED.value(), result); HttpResponseUtils.flushResponseJson(response, UNAUTHORIZED.value(), result);
} }
public ConsoleAuthenticationEntryPoint(UserAgentParser userAgentParser) {
super(userAgentParser);
}
} }

View File

@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import cn.topiam.employee.EiamConsoleApplication; import cn.topiam.employee.EiamConsoleApplication;
import cn.topiam.employee.support.util.AppVersionUtils; import cn.topiam.employee.support.util.VersionUtils;
import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.OpenAPI;
@ -59,7 +59,7 @@ public class ConsoleApiConfiguration {
//内容 //内容
.contact(contact) .contact(contact)
//版本 //版本
.version(AppVersionUtils.getVersion(EiamConsoleApplication.class)); .version(VersionUtils.getVersion(EiamConsoleApplication.class));
} }
/** /**

View File

@ -58,11 +58,12 @@ import cn.topiam.employee.common.entity.setting.SettingEntity;
import cn.topiam.employee.common.repository.setting.AdministratorRepository; import cn.topiam.employee.common.repository.setting.AdministratorRepository;
import cn.topiam.employee.common.repository.setting.SettingRepository; import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.console.authentication.*; import cn.topiam.employee.console.authentication.*;
import cn.topiam.employee.support.geo.GeoLocationService; import cn.topiam.employee.support.geo.GeoLocationParser;
import cn.topiam.employee.support.jackjson.SupportJackson2Module; import cn.topiam.employee.support.jackjson.SupportJackson2Module;
import cn.topiam.employee.support.security.authentication.WebAuthenticationDetailsSource; import cn.topiam.employee.support.security.authentication.WebAuthenticationDetailsSource;
import cn.topiam.employee.support.security.configurer.FormLoginConfigurer; import cn.topiam.employee.support.security.configurer.FormLoginConfigurer;
import cn.topiam.employee.support.security.csrf.SpaCsrfTokenRequestHandler; import cn.topiam.employee.support.security.csrf.SpaCsrfTokenRequestHandler;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.Customizer.withDefaults;
@ -247,7 +248,8 @@ public class ConsoleSecurityConfiguration implements BeanClassLoaderAware {
*/ */
public Customizer<ExceptionHandlingConfigurer<HttpSecurity>> withExceptionConfigurerDefaults() { public Customizer<ExceptionHandlingConfigurer<HttpSecurity>> withExceptionConfigurerDefaults() {
return configurer -> { return configurer -> {
configurer.authenticationEntryPoint(new ConsoleAuthenticationEntryPoint()); configurer
.authenticationEntryPoint(new ConsoleAuthenticationEntryPoint(userAgentParser));
configurer.accessDeniedHandler(new ConsoleAccessDeniedHandler()); configurer.accessDeniedHandler(new ConsoleAccessDeniedHandler());
configurer configurer
.withObjectPostProcessor(new ObjectPostProcessor<ExceptionTranslationFilter>() { .withObjectPostProcessor(new ObjectPostProcessor<ExceptionTranslationFilter>() {
@ -353,12 +355,13 @@ public class ConsoleSecurityConfiguration implements BeanClassLoaderAware {
/** /**
* WebAuthenticationDetailsSource * WebAuthenticationDetailsSource
* *
* @param geoLocationService {@link GeoLocationService} * @param geoLocationParser {@link GeoLocationParser}
* @return {@link WebAuthenticationDetailsSource} * @return {@link WebAuthenticationDetailsSource}
*/ */
@Bean @Bean
public WebAuthenticationDetailsSource authenticationDetailsSource(GeoLocationService geoLocationService) { public WebAuthenticationDetailsSource authenticationDetailsSource(GeoLocationParser geoLocationParser,
return new WebAuthenticationDetailsSource(geoLocationService); UserAgentParser userAgentParser) {
return new WebAuthenticationDetailsSource(geoLocationParser, userAgentParser);
} }
private ClassLoader loader; private ClassLoader loader;
@ -383,4 +386,9 @@ public class ConsoleSecurityConfiguration implements BeanClassLoaderAware {
*/ */
private final AuditEventPublish auditEventPublish; private final AuditEventPublish auditEventPublish;
/**
* UserAgentParser
*/
private final UserAgentParser userAgentParser;
} }

View File

@ -32,15 +32,16 @@ import cn.topiam.employee.common.exception.UserNotFoundException;
import cn.topiam.employee.common.repository.setting.AdministratorRepository; import cn.topiam.employee.common.repository.setting.AdministratorRepository;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.util.DesensitizationUtil;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import static cn.topiam.employee.common.constant.SessionConstants.CURRENT_USER; import static cn.topiam.employee.common.constant.SessionConstants.CURRENT_USER;
import static cn.topiam.employee.support.util.ImageAvatarUtils.bufferedImageToBase64; import static cn.topiam.employee.support.util.AvatarUtils.bufferedImageToBase64;
import static cn.topiam.employee.support.util.ImageAvatarUtils.generateAvatarImg; import static cn.topiam.employee.support.util.AvatarUtils.generateAvatarImg;
import static cn.topiam.employee.support.util.DesensitizationUtils.emailEncrypt;
import static cn.topiam.employee.support.util.DesensitizationUtils.phoneEncrypt;
/** /**
* *
@ -81,9 +82,9 @@ public class CurrentUserEndpoint {
result.setAvatar(administrator.getAvatar()); result.setAvatar(administrator.getAvatar());
} }
//邮箱 //邮箱
result.setEmail(DesensitizationUtil.emailEncrypt(administrator.getEmail())); result.setEmail(emailEncrypt(administrator.getEmail()));
//手机号 //手机号
result.setPhone(DesensitizationUtil.phoneEncrypt(administrator.getPhone())); result.setPhone(phoneEncrypt(administrator.getPhone()));
return ApiRestResult.ok(result); return ApiRestResult.ok(result);
} }

View File

@ -31,8 +31,8 @@ import cn.topiam.employee.console.pojo.result.account.*;
import cn.topiam.employee.console.pojo.save.account.OrganizationCreateParam; import cn.topiam.employee.console.pojo.save.account.OrganizationCreateParam;
import cn.topiam.employee.console.pojo.update.account.OrganizationUpdateParam; import cn.topiam.employee.console.pojo.update.account.OrganizationUpdateParam;
import cn.topiam.employee.console.service.account.OrganizationService; import cn.topiam.employee.console.service.account.OrganizationService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Operation;

View File

@ -41,8 +41,8 @@ import cn.topiam.employee.console.pojo.update.account.UserUpdateParam;
import cn.topiam.employee.console.service.account.UserService; import cn.topiam.employee.console.service.account.UserService;
import cn.topiam.employee.console.service.app.UserIdpBindService; import cn.topiam.employee.console.service.app.UserIdpBindService;
import cn.topiam.employee.core.security.otp.OtpContextHelp; import cn.topiam.employee.core.security.otp.OtpContextHelp;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -38,8 +38,8 @@ import cn.topiam.employee.console.pojo.save.account.UserCreateParam;
import cn.topiam.employee.console.pojo.save.account.UserGroupCreateParam; import cn.topiam.employee.console.pojo.save.account.UserGroupCreateParam;
import cn.topiam.employee.console.pojo.update.account.UserGroupUpdateParam; import cn.topiam.employee.console.pojo.update.account.UserGroupUpdateParam;
import cn.topiam.employee.console.service.account.UserGroupService; import cn.topiam.employee.console.service.account.UserGroupService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -29,8 +29,8 @@ import cn.topiam.employee.console.pojo.result.app.AppAccessPolicyResult;
import cn.topiam.employee.console.pojo.save.app.AppAccessPolicyCreateParam; import cn.topiam.employee.console.pojo.save.app.AppAccessPolicyCreateParam;
import cn.topiam.employee.console.pojo.save.app.AppAccountCreateParam; import cn.topiam.employee.console.pojo.save.app.AppAccountCreateParam;
import cn.topiam.employee.console.service.app.AppAccessPolicyService; import cn.topiam.employee.console.service.app.AppAccessPolicyService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -28,8 +28,8 @@ import cn.topiam.employee.common.entity.app.query.AppAccountQuery;
import cn.topiam.employee.console.pojo.result.app.AppAccountListResult; import cn.topiam.employee.console.pojo.result.app.AppAccountListResult;
import cn.topiam.employee.console.pojo.save.app.AppAccountCreateParam; import cn.topiam.employee.console.pojo.save.app.AppAccountCreateParam;
import cn.topiam.employee.console.service.app.AppAccountService; import cn.topiam.employee.console.service.app.AppAccountService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -32,8 +32,8 @@ import cn.topiam.employee.console.pojo.save.app.AppCreateParam;
import cn.topiam.employee.console.pojo.update.app.AppSaveConfigParam; import cn.topiam.employee.console.pojo.update.app.AppSaveConfigParam;
import cn.topiam.employee.console.pojo.update.app.AppUpdateParam; import cn.topiam.employee.console.pojo.update.app.AppUpdateParam;
import cn.topiam.employee.console.service.app.AppService; import cn.topiam.employee.console.service.app.AppService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -35,8 +35,8 @@ import cn.topiam.employee.console.pojo.result.app.AppListResult;
import cn.topiam.employee.console.pojo.save.app.AppGroupCreateParam; import cn.topiam.employee.console.pojo.save.app.AppGroupCreateParam;
import cn.topiam.employee.console.pojo.update.app.AppGroupUpdateParam; import cn.topiam.employee.console.pojo.update.app.AppGroupUpdateParam;
import cn.topiam.employee.console.service.app.AppGroupService; import cn.topiam.employee.console.service.app.AppGroupService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -32,8 +32,8 @@ import cn.topiam.employee.console.pojo.result.authn.IdentityProviderResult;
import cn.topiam.employee.console.pojo.save.authn.IdentityProviderCreateParam; import cn.topiam.employee.console.pojo.save.authn.IdentityProviderCreateParam;
import cn.topiam.employee.console.pojo.update.authn.IdpUpdateParam; import cn.topiam.employee.console.pojo.update.authn.IdpUpdateParam;
import cn.topiam.employee.console.service.authn.IdentityProviderService; import cn.topiam.employee.console.service.authn.IdentityProviderService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -37,8 +37,8 @@ import cn.topiam.employee.console.pojo.save.identitysource.IdentitySourceCreateR
import cn.topiam.employee.console.pojo.update.identity.IdentitySourceUpdateParam; import cn.topiam.employee.console.pojo.update.identity.IdentitySourceUpdateParam;
import cn.topiam.employee.console.service.identitysource.IdentitySourceService; import cn.topiam.employee.console.service.identitysource.IdentitySourceService;
import cn.topiam.employee.identitysource.core.event.IdentitySourceEventUtils; import cn.topiam.employee.identitysource.core.event.IdentitySourceEventUtils;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -29,8 +29,8 @@ import cn.topiam.employee.console.pojo.query.identity.IdentitySourceSyncRecordLi
import cn.topiam.employee.console.pojo.result.identitysource.IdentitySourceSyncHistoryListResult; import cn.topiam.employee.console.pojo.result.identitysource.IdentitySourceSyncHistoryListResult;
import cn.topiam.employee.console.pojo.result.identitysource.IdentitySourceSyncRecordListResult; import cn.topiam.employee.console.pojo.result.identitysource.IdentitySourceSyncRecordListResult;
import cn.topiam.employee.console.service.identitysource.IdentitySourceSyncService; import cn.topiam.employee.console.service.identitysource.IdentitySourceSyncService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -46,9 +46,9 @@ import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.core.security.session.ClusterSessionRegistryImpl; import cn.topiam.employee.core.security.session.ClusterSessionRegistryImpl;
import cn.topiam.employee.core.security.session.Session; import cn.topiam.employee.core.security.session.Session;
import cn.topiam.employee.support.context.ApplicationContextService; import cn.topiam.employee.support.context.ApplicationContextService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.geo.GeoLocation; import cn.topiam.employee.support.geo.GeoLocation;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.web.useragent.UserAgent; import cn.topiam.employee.support.web.useragent.UserAgent;

View File

@ -32,8 +32,8 @@ import cn.topiam.employee.console.pojo.result.setting.AdministratorResult;
import cn.topiam.employee.console.pojo.save.setting.AdministratorCreateParam; import cn.topiam.employee.console.pojo.save.setting.AdministratorCreateParam;
import cn.topiam.employee.console.pojo.update.setting.AdministratorUpdateParam; import cn.topiam.employee.console.pojo.update.setting.AdministratorUpdateParam;
import cn.topiam.employee.console.service.setting.AdministratorService; import cn.topiam.employee.console.service.setting.AdministratorService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;

View File

@ -28,9 +28,9 @@ import cn.topiam.employee.console.pojo.result.setting.GeoIpProviderResult;
import cn.topiam.employee.console.pojo.save.setting.GeoIpProviderSaveParam; import cn.topiam.employee.console.pojo.save.setting.GeoIpProviderSaveParam;
import cn.topiam.employee.console.service.setting.GeoLocationSettingService; import cn.topiam.employee.console.service.setting.GeoLocationSettingService;
import cn.topiam.employee.support.context.ApplicationContextService; import cn.topiam.employee.support.context.ApplicationContextService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.geo.GeoLocation; import cn.topiam.employee.support.geo.GeoLocation;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -33,8 +33,8 @@ import cn.topiam.employee.console.service.setting.MessageSettingService;
import cn.topiam.employee.core.context.ContextService; import cn.topiam.employee.core.context.ContextService;
import cn.topiam.employee.core.message.MsgVariable; import cn.topiam.employee.core.message.MsgVariable;
import cn.topiam.employee.core.message.mail.MailMsgEventPublish; import cn.topiam.employee.core.message.mail.MailMsgEventPublish;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -32,8 +32,8 @@ import cn.topiam.employee.console.pojo.result.setting.EmailTemplateListResult;
import cn.topiam.employee.console.pojo.result.setting.EmailTemplateResult; import cn.topiam.employee.console.pojo.result.setting.EmailTemplateResult;
import cn.topiam.employee.console.pojo.save.setting.EmailCustomTemplateSaveParam; import cn.topiam.employee.console.pojo.save.setting.EmailCustomTemplateSaveParam;
import cn.topiam.employee.console.service.setting.MailTemplateService; import cn.topiam.employee.console.service.setting.MailTemplateService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -27,8 +27,8 @@ import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.console.pojo.result.setting.SecurityBasicConfigResult; import cn.topiam.employee.console.pojo.result.setting.SecurityBasicConfigResult;
import cn.topiam.employee.console.pojo.save.setting.SecurityBasicSaveParam; import cn.topiam.employee.console.pojo.save.setting.SecurityBasicSaveParam;
import cn.topiam.employee.console.service.setting.SecuritySettingService; import cn.topiam.employee.console.service.setting.SecuritySettingService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -27,8 +27,8 @@ import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.console.pojo.result.setting.SecurityDefensePolicyConfigResult; import cn.topiam.employee.console.pojo.result.setting.SecurityDefensePolicyConfigResult;
import cn.topiam.employee.console.pojo.save.setting.SecurityDefensePolicyParam; import cn.topiam.employee.console.pojo.save.setting.SecurityDefensePolicyParam;
import cn.topiam.employee.console.service.setting.SecurityDefensePolicyService; import cn.topiam.employee.console.service.setting.SecurityDefensePolicyService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -30,8 +30,8 @@ import cn.topiam.employee.console.pojo.result.setting.PasswordPolicyConfigResult
import cn.topiam.employee.console.pojo.result.setting.WeakPasswordLibListResult; import cn.topiam.employee.console.pojo.result.setting.WeakPasswordLibListResult;
import cn.topiam.employee.console.pojo.save.setting.PasswordPolicySaveParam; import cn.topiam.employee.console.pojo.save.setting.PasswordPolicySaveParam;
import cn.topiam.employee.console.service.setting.PasswordPolicyService; import cn.topiam.employee.console.service.setting.PasswordPolicyService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -33,8 +33,8 @@ import cn.topiam.employee.console.pojo.save.setting.SmsProviderSaveParam;
import cn.topiam.employee.console.service.setting.MessageSettingService; import cn.topiam.employee.console.service.setting.MessageSettingService;
import cn.topiam.employee.core.message.MsgVariable; import cn.topiam.employee.core.message.MsgVariable;
import cn.topiam.employee.core.message.sms.SmsMsgEventPublish; import cn.topiam.employee.core.message.sms.SmsMsgEventPublish;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.security.password.PasswordGenerator; import cn.topiam.employee.support.security.password.PasswordGenerator;

View File

@ -27,8 +27,8 @@ import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.console.pojo.result.setting.StorageProviderConfigResult; import cn.topiam.employee.console.pojo.result.setting.StorageProviderConfigResult;
import cn.topiam.employee.console.pojo.save.setting.StorageConfigSaveParam; import cn.topiam.employee.console.pojo.save.setting.StorageConfigSaveParam;
import cn.topiam.employee.console.service.setting.StorageSettingService; import cn.topiam.employee.console.service.setting.StorageSettingService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -56,9 +56,9 @@ import static cn.topiam.employee.audit.enums.TargetType.PORTAL;
import static cn.topiam.employee.audit.event.type.EventType.APP_SSO; import static cn.topiam.employee.audit.event.type.EventType.APP_SSO;
import static cn.topiam.employee.audit.event.type.EventType.LOGIN_PORTAL; import static cn.topiam.employee.audit.event.type.EventType.LOGIN_PORTAL;
import static cn.topiam.employee.audit.service.converter.AuditDataConverter.SORT_EVENT_TIME; import static cn.topiam.employee.audit.service.converter.AuditDataConverter.SORT_EVENT_TIME;
import static cn.topiam.employee.support.util.ImageAvatarUtils.*; import static cn.topiam.employee.support.util.AvatarUtils.*;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneAreaCode; import static cn.topiam.employee.support.util.PhoneUtils.getPhoneAreaCode;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.getPhoneNumber;
/** /**
* *

View File

@ -35,15 +35,15 @@ import cn.topiam.employee.console.pojo.save.setting.AdministratorCreateParam;
import cn.topiam.employee.console.pojo.update.setting.AdministratorUpdateParam; import cn.topiam.employee.console.pojo.update.setting.AdministratorUpdateParam;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.util.BeanUtils; import cn.topiam.employee.support.util.BeanUtils;
import cn.topiam.employee.support.util.ImageAvatarUtils;
import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Predicate;
import static cn.topiam.employee.common.entity.setting.AdministratorEntity.*; import static cn.topiam.employee.common.entity.setting.AdministratorEntity.*;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
import static cn.topiam.employee.support.util.ImageAvatarUtils.generateAvatarImg; import static cn.topiam.employee.support.util.AvatarUtils.bufferedImageToBase64;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneAreaCode; import static cn.topiam.employee.support.util.AvatarUtils.generateAvatarImg;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.getPhoneAreaCode;
import static cn.topiam.employee.support.util.PhoneUtils.getPhoneNumber;
/** /**
* *
@ -69,8 +69,7 @@ public interface AdministratorConverter {
user); user);
//头像 //头像
if (StringUtils.isEmpty(user.getAvatar())) { if (StringUtils.isEmpty(user.getAvatar())) {
convert.setAvatar(ImageAvatarUtils convert.setAvatar(bufferedImageToBase64(generateAvatarImg(user.getUsername())));
.bufferedImageToBase64(generateAvatarImg(user.getUsername())));
} else { } else {
convert.setAvatar(user.getAvatar()); convert.setAvatar(user.getAvatar());
} }

View File

@ -44,8 +44,8 @@ import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.validation.ValidationUtils; import cn.topiam.employee.support.validation.ValidationUtils;
import jakarta.validation.ValidationException; import jakarta.validation.ValidationException;
import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationServiceImpl.MAXMIND; import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationParserImpl.MAXMIND;
import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationServiceImpl.SHA256_URL; import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationParserImpl.SHA256_URL;
import static cn.topiam.employee.core.setting.GeoIpProviderConstants.IPADDRESS_SETTING_NAME; import static cn.topiam.employee.core.setting.GeoIpProviderConstants.IPADDRESS_SETTING_NAME;
/** /**

View File

@ -70,8 +70,7 @@ import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.security.password.PasswordPolicyManager; import cn.topiam.employee.support.security.password.PasswordPolicyManager;
import cn.topiam.employee.support.util.BeanUtils; import cn.topiam.employee.support.util.BeanUtils;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import cn.topiam.employee.support.validation.annotation.ValidationPhone;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -80,7 +79,8 @@ import static cn.topiam.employee.audit.enums.TargetType.USER_DETAIL;
import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME; import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.PHONE_REGEXP;
import static cn.topiam.employee.support.util.PhoneUtils.getPhoneNumber;
/** /**
* <p> * <p>
@ -216,7 +216,7 @@ public class UserServiceImpl implements UserService {
} }
//手机号 //手机号
if (StringUtils.isNotEmpty(param.getPhone())) { if (StringUtils.isNotEmpty(param.getPhone())) {
if (!getPhoneNumber(param.getPhone()).matches(ValidationPhone.PHONE_REGEXP)) { if (!getPhoneNumber(param.getPhone()).matches(PHONE_REGEXP)) {
throw new InfoValidityFailException("手机号格式错误"); throw new InfoValidityFailException("手机号格式错误");
} }
Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), null); Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), null);
@ -306,8 +306,8 @@ public class UserServiceImpl implements UserService {
detail.orElse(null)); detail.orElse(null));
if (Objects.nonNull(userEntity) && StringUtils.isNotEmpty(userEntity.getPhone())) { if (Objects.nonNull(userEntity) && StringUtils.isNotEmpty(userEntity.getPhone())) {
StringBuilder phoneAreaCode = new StringBuilder( StringBuilder phoneAreaCode = new StringBuilder(
userEntity.getPhoneAreaCode().replace(PhoneNumberUtils.PLUS_SIGN, "")); userEntity.getPhoneAreaCode().replace(PhoneUtils.PLUS_SIGN, ""));
phoneAreaCode.insert(0, PhoneNumberUtils.PLUS_SIGN); phoneAreaCode.insert(0, PhoneUtils.PLUS_SIGN);
userResult.setPhone(phoneAreaCode + userEntity.getPhone()); userResult.setPhone(phoneAreaCode + userEntity.getPhone());
} }
return userResult; return userResult;
@ -324,7 +324,7 @@ public class UserServiceImpl implements UserService {
public boolean updateUser(UserUpdateParam param) { public boolean updateUser(UserUpdateParam param) {
if (StringUtils.isNotBlank(param.getPhone())) { if (StringUtils.isNotBlank(param.getPhone())) {
String phoneNumber = getPhoneNumber(param.getPhone()); String phoneNumber = getPhoneNumber(param.getPhone());
if (!phoneNumber.matches(ValidationPhone.PHONE_REGEXP)) { if (!phoneNumber.matches(PHONE_REGEXP)) {
throw new InfoValidityFailException("手机号格式错误"); throw new InfoValidityFailException("手机号格式错误");
} }
Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(),
@ -440,7 +440,7 @@ public class UserServiceImpl implements UserService {
if (CheckValidityType.PHONE.equals(type)) { if (CheckValidityType.PHONE.equals(type)) {
try { try {
//手机号未修改 //手机号未修改
if (StringUtils.equals(value.replace(PhoneNumberUtils.PLUS_SIGN, ""), if (StringUtils.equals(value.replace(PhoneUtils.PLUS_SIGN, ""),
entity.getPhoneAreaCode() + entity.getPhone())) { entity.getPhoneAreaCode() + entity.getPhone())) {
return true; return true;
} }
@ -514,70 +514,70 @@ public class UserServiceImpl implements UserService {
/** /**
* *
*/ */
private final UserConverter userConverter; private final UserConverter userConverter;
/** /**
* UserRepository * UserRepository
*/ */
private final UserRepository userRepository; private final UserRepository userRepository;
/** /**
* UserIdpRepository * UserIdpRepository
*/ */
private final UserIdpRepository userIdpRepository; private final UserIdpRepository userIdpRepository;
/** /**
* AppAccessPolicyRepository * AppAccessPolicyRepository
*/ */
private final AppAccessPolicyRepository appAccessPolicyRepository; private final AppAccessPolicyRepository appAccessPolicyRepository;
/** /**
* password encoder * password encoder
*/ */
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
/** /**
* *
*/ */
private final OrganizationRepository organizationRepository; private final OrganizationRepository organizationRepository;
/** /**
* *
*/ */
private final OrganizationMemberRepository organizationMemberRepository; private final OrganizationMemberRepository organizationMemberRepository;
/** /**
* *
*/ */
private final UserGroupMemberRepository userGroupMemberRepository; private final UserGroupMemberRepository userGroupMemberRepository;
/** /**
* Repository * Repository
*/ */
private final UserDetailRepository userDetailsRepository; private final UserDetailRepository userDetailsRepository;
/** /**
* Repository * Repository
*/ */
private final UserHistoryPasswordRepository userHistoryPasswordRepository; private final UserHistoryPasswordRepository userHistoryPasswordRepository;
/** /**
* *
*/ */
private final MailMsgEventPublish mailMsgEventPublish; private final MailMsgEventPublish mailMsgEventPublish;
/** /**
* *
*/ */
private final SmsMsgEventPublish smsMsgEventPublish; private final SmsMsgEventPublish smsMsgEventPublish;
/** /**
* PasswordPolicyManager * PasswordPolicyManager
*/ */
private final PasswordPolicyManager<UserEntity> passwordPolicyManager; private final PasswordPolicyManager passwordPolicyManager;
/** /**
* AuditRepository * AuditRepository
*/ */
private final AuditRepository auditRepository; private final AuditRepository auditRepository;
} }

View File

@ -17,6 +17,7 @@
*/ */
package cn.topiam.employee.console.service.account.userdetail; package cn.topiam.employee.console.service.account.userdetail;
import java.time.LocalDateTime;
import java.util.Optional; import java.util.Optional;
import org.slf4j.Logger; import org.slf4j.Logger;
@ -25,8 +26,13 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import cn.topiam.employee.audit.context.AuditContext;
import cn.topiam.employee.audit.entity.Target;
import cn.topiam.employee.audit.enums.TargetType;
import cn.topiam.employee.common.entity.setting.AdministratorEntity; import cn.topiam.employee.common.entity.setting.AdministratorEntity;
import cn.topiam.employee.common.repository.setting.AdministratorRepository;
import cn.topiam.employee.console.service.setting.AdministratorService; import cn.topiam.employee.console.service.setting.AdministratorService;
import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException; import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException;
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.security.userdetails.UserDetailsService; import cn.topiam.employee.support.security.userdetails.UserDetailsService;
@ -75,36 +81,103 @@ public class UserDetailsServiceImpl implements UserDetailsService {
return administratorService.getUserDetails(administrator); return administratorService.getUserDetails(administrator);
} }
@Override
public UserDetails loadUserByPhone(String phone) throws UsernameNotFoundException {
Optional<AdministratorEntity> optional = administratorRepository.findByPhone(phone);
//不存在该用户
if (optional.isEmpty()) {
logger.info("根据手机号未查询该管理员【{}】", phone);
throw new UsernameNotFoundException("用户名或密码错误");
}
return getUserDetails(optional.get());
}
@Override
public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException {
Optional<AdministratorEntity> optional = administratorRepository.findByEmail(email);
//不存在该用户
if (optional.isEmpty()) {
logger.info("根据邮箱未查询该管理员【{}】", email);
throw new UsernameNotFoundException("用户名或密码错误");
}
return getUserDetails(optional.get());
}
@Override @Override
public void changePassword(String username, String newPassword) { public void changePassword(String username, String newPassword) {
administratorService.forceResetAdministratorPassword(username, newPassword); AdministratorEntity administrator = findByUsername(username);
forceResetUserPassword(administrator, newPassword);
} }
@Override @Override
public void changePassword(String username, String oldPassword, String newPassword) { public void changePassword(String username, String oldPassword, String newPassword) {
AdministratorEntity admin = administratorService.getAdministratorByUsername(username); AdministratorEntity administrator = findByUsername(username);
boolean matches = passwordEncoder.matches(oldPassword, admin.getPassword()); boolean matches = passwordEncoder.matches(oldPassword, administrator.getPassword());
if (!matches) { if (!matches) {
logger.error("用户ID: [{}] 用户名: [{}] 旧密码匹配失败", admin.getId(), admin.getUsername()); logger.error("用户ID: [{}] 用户名: [{}] 旧密码匹配失败", administrator.getId(),
administrator.getUsername());
throw new PasswordValidatedFailException(); throw new PasswordValidatedFailException();
} }
// 重置密码 forceResetUserPassword(administrator, newPassword);
administratorService.forceResetAdministratorPassword(admin, newPassword); }
private UserDetails getUserDetails(AdministratorEntity administrator) {
//锁定
if (administrator.isLocked()) {
logger.info("用户【{}】被锁定", administrator.getUsername());
}
//禁用
if (administrator.isDisabled()) {
logger.info("用户【{}】被禁用", administrator.getUsername());
}
return administratorService.getUserDetails(administrator);
}
public void forceResetUserPassword(AdministratorEntity administrator, String password) {
boolean matches = passwordEncoder.matches(password, administrator.getPassword());
if (matches) {
logger.error("用户ID: [{}] 用户名: [{}] 新密码与旧密码相同", administrator.getId(),
administrator.getUsername());
throw new PasswordValidatedFailException("新密码不允许与旧密码相同");
}
password = passwordEncoder.encode(password);
administrator.setPassword(password);
administrator.setLastUpdatePasswordTime(LocalDateTime.now());
administrator.setNeedChangePassword(false);
// 更新密码
administratorRepository.save(administrator);
AuditContext.setTarget(Target.builder().id(administrator.getId())
.name(administrator.getUsername()).type(TargetType.USER).build());
}
public AdministratorEntity findByUsername(String username) {
return administratorRepository.findByUsername(username).orElseThrow(() -> {
AuditContext.setContent("重置密码失败,用户不存在");
logger.warn(AuditContext.getContent());
return new TopIamException("操作失败");
});
} }
/** /**
* AdministratorService * AdministratorRepository
*/ */
private final AdministratorService administratorService; private final AdministratorRepository administratorRepository;
/** /**
* PasswordEncoder * PasswordEncoder
*/ */
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
public UserDetailsServiceImpl(AdministratorService administratorService, /**
PasswordEncoder passwordEncoder) { * UserService
this.administratorService = administratorService; */
private final AdministratorService administratorService;
public UserDetailsServiceImpl(AdministratorRepository administratorRepository,
PasswordEncoder passwordEncoder,
AdministratorService administratorService) {
this.administratorRepository = administratorRepository;
this.passwordEncoder = passwordEncoder; this.passwordEncoder = passwordEncoder;
this.administratorService = administratorService;
} }
} }

View File

@ -69,10 +69,9 @@ import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException; import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException;
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.security.userdetails.UserType; import cn.topiam.employee.support.security.userdetails.UserType;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import cn.topiam.employee.support.validation.annotation.ValidationPhone;
import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_ADMIN_USERNAME; import static cn.topiam.employee.support.constant.EiamConstants.DEFAULT_ADMIN_USERNAME;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.*;
/** /**
* @author TopIAM * @author TopIAM
@ -115,7 +114,7 @@ public class AdministratorServiceImpl implements AdministratorService {
} }
//手机号 //手机号
if (StringUtils.isNotEmpty(param.getPhone())) { if (StringUtils.isNotEmpty(param.getPhone())) {
if (!getPhoneNumber(param.getPhone()).matches(ValidationPhone.PHONE_REGEXP)) { if (!getPhoneNumber(param.getPhone()).matches(PHONE_REGEXP)) {
throw new InfoValidityFailException("手机号格式错误"); throw new InfoValidityFailException("手机号格式错误");
} }
Boolean validityPhone = administratorParamCheck(CheckValidityType.PHONE, param.getPhone(), null); Boolean validityPhone = administratorParamCheck(CheckValidityType.PHONE, param.getPhone(), null);
@ -331,7 +330,7 @@ public class AdministratorServiceImpl implements AdministratorService {
if (CheckValidityType.PHONE.equals(type)) { if (CheckValidityType.PHONE.equals(type)) {
try { try {
//手机号未修改 //手机号未修改
if (StringUtils.equals(value.replace(PhoneNumberUtils.PLUS_SIGN, ""), if (StringUtils.equals(value.replace(PLUS_SIGN, ""),
entity.getPhoneAreaCode() + entity.getPhone())) { entity.getPhoneAreaCode() + entity.getPhone())) {
return true; return true;
} }
@ -443,8 +442,8 @@ public class AdministratorServiceImpl implements AdministratorService {
.entityConvertToAdministratorDetailsResult(administrator); .entityConvertToAdministratorDetailsResult(administrator);
if (Objects.nonNull(administrator) && StringUtils.isNotEmpty(administrator.getPhone())) { if (Objects.nonNull(administrator) && StringUtils.isNotEmpty(administrator.getPhone())) {
StringBuilder phoneAreaCode = new StringBuilder( StringBuilder phoneAreaCode = new StringBuilder(
administrator.getPhoneAreaCode().replace(PhoneNumberUtils.PLUS_SIGN, "")); administrator.getPhoneAreaCode().replace(PhoneUtils.PLUS_SIGN, ""));
phoneAreaCode.insert(0, PhoneNumberUtils.PLUS_SIGN); phoneAreaCode.insert(0, PhoneUtils.PLUS_SIGN);
result.setPhone(phoneAreaCode + administrator.getPhone()); result.setPhone(phoneAreaCode + administrator.getPhone());
} }
return result; return result;

View File

@ -28,7 +28,7 @@ import cn.topiam.employee.console.pojo.save.setting.GeoIpProviderSaveParam;
import cn.topiam.employee.console.service.setting.GeoLocationSettingService; import cn.topiam.employee.console.service.setting.GeoLocationSettingService;
import cn.topiam.employee.support.context.ApplicationContextService; import cn.topiam.employee.support.context.ApplicationContextService;
import cn.topiam.employee.support.geo.GeoLocation; import cn.topiam.employee.support.geo.GeoLocation;
import cn.topiam.employee.support.geo.GeoLocationService; import cn.topiam.employee.support.geo.GeoLocationParser;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.GEO_LOCATION; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.GEO_LOCATION;
@ -80,17 +80,17 @@ public class GeoLocationSettingServiceImpl extends SettingServiceImpl
*/ */
@Override @Override
public GeoLocation getGeoLocation(String ip) { public GeoLocation getGeoLocation(String ip) {
return geoLocationService.getGeoLocation(ip); return geoLocationParser.getGeoLocation(ip);
} }
private final GeoLocationService geoLocationService; private final GeoLocationParser geoLocationParser;
private final GeoLocationSettingConverter geoLocationSettingsConverter; private final GeoLocationSettingConverter geoLocationSettingsConverter;
public GeoLocationSettingServiceImpl(SettingRepository settingsRepository, public GeoLocationSettingServiceImpl(SettingRepository settingsRepository,
GeoLocationService geoLocationService, GeoLocationParser geoLocationParser,
GeoLocationSettingConverter geoLocationSettingsConverter) { GeoLocationSettingConverter geoLocationSettingsConverter) {
super(settingsRepository); super(settingsRepository);
this.geoLocationService = geoLocationService; this.geoLocationParser = geoLocationParser;
this.geoLocationSettingsConverter = geoLocationSettingsConverter; this.geoLocationSettingsConverter = geoLocationSettingsConverter;
} }
} }

View File

@ -55,7 +55,7 @@ import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException; import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException;
import cn.topiam.employee.support.security.util.SecurityUtils; import cn.topiam.employee.support.security.util.SecurityUtils;
import cn.topiam.employee.support.util.BeanUtils; import cn.topiam.employee.support.util.BeanUtils;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import jakarta.servlet.http.HttpSession; import jakarta.servlet.http.HttpSession;
import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME; import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME;
@ -64,7 +64,7 @@ import static cn.topiam.employee.support.exception.enums.ExceptionStatus.EX00010
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
import static cn.topiam.employee.support.util.EmailUtils.isEmailValidate; import static cn.topiam.employee.support.util.EmailUtils.isEmailValidate;
import static cn.topiam.employee.support.util.PhoneNumberUtils.isPhoneValidate; import static cn.topiam.employee.support.util.PhoneUtils.isPhoneValidate;
/** /**
* *
@ -229,7 +229,7 @@ public class UserProfileServiceImpl implements UserProfileService {
} else if (isPhoneValidate(recipient)) { } else if (isPhoneValidate(recipient)) {
// 验证在库中是否有手机号 // 验证在库中是否有手机号
Optional<AdministratorEntity> byPhone = administratorRepository Optional<AdministratorEntity> byPhone = administratorRepository
.findByPhone(PhoneNumberUtils.getPhoneNumber(recipient)); .findByPhone(PhoneUtils.getPhoneNumber(recipient));
if (byPhone.isPresent()) { if (byPhone.isPresent()) {
otpContextHelp.sendOtp(recipient, SmsType.FORGET_PASSWORD.getCode(), otpContextHelp.sendOtp(recipient, SmsType.FORGET_PASSWORD.getCode(),
MessageNoticeChannel.SMS); MessageNoticeChannel.SMS);
@ -253,7 +253,7 @@ public class UserProfileServiceImpl implements UserProfileService {
MessageNoticeChannel.MAIL, recipient, code); MessageNoticeChannel.MAIL, recipient, code);
} }
} else if (isPhoneValidate(recipient)) { } else if (isPhoneValidate(recipient)) {
user = administratorRepository.findByPhone(PhoneNumberUtils.getPhoneNumber(recipient)); user = administratorRepository.findByPhone(PhoneUtils.getPhoneNumber(recipient));
if (user.isPresent()) { if (user.isPresent()) {
checkOtp = otpContextHelp.checkOtp(SmsType.FORGET_PASSWORD.getCode(), checkOtp = otpContextHelp.checkOtp(SmsType.FORGET_PASSWORD.getCode(),
MessageNoticeChannel.SMS, recipient, code); MessageNoticeChannel.SMS, recipient, code);

View File

@ -33,17 +33,17 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import cn.topiam.employee.common.entity.setting.SettingEntity; import cn.topiam.employee.common.entity.setting.SettingEntity;
import cn.topiam.employee.common.geo.GeoLocationProviderConfig; import cn.topiam.employee.common.geo.GeoLocationProviderConfig;
import cn.topiam.employee.common.geo.NoneGeoLocationServiceImpl; import cn.topiam.employee.common.geo.NoneGeoLocationParserImpl;
import cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationServiceImpl; import cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationParserImpl;
import cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationServiceImpl; import cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationParserImpl;
import cn.topiam.employee.common.geo.maxmind.MaxmindProviderConfig; import cn.topiam.employee.common.geo.maxmind.MaxmindProviderConfig;
import cn.topiam.employee.common.jackjson.encrypt.EncryptionModule; import cn.topiam.employee.common.jackjson.encrypt.EncryptionModule;
import cn.topiam.employee.common.repository.setting.SettingRepository; import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.core.setting.GeoIpProviderConstants; import cn.topiam.employee.core.setting.GeoIpProviderConstants;
import cn.topiam.employee.support.geo.GeoLocationService; import cn.topiam.employee.support.geo.GeoLocationParser;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.GEO_LOCATION; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.GEO_LOCATION;
import static cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationServiceImpl.IP2REGION; import static cn.topiam.employee.common.geo.ip2region.Ip2regionGeoLocationParserImpl.IP2REGION;
import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationServiceImpl.MAXMIND; import static cn.topiam.employee.common.geo.maxmind.MaxmindGeoLocationParserImpl.MAXMIND;
/** /**
* *
@ -57,8 +57,8 @@ public class EiamGeoLocationConfiguration {
@RefreshScope @RefreshScope
@Bean(value = GEO_LOCATION) @Bean(value = GEO_LOCATION)
public GeoLocationService geoLocation(SettingRepository settingRepository, public GeoLocationParser geoLocation(SettingRepository settingRepository,
RestTemplate restTemplate) { RestTemplate restTemplate) {
try { try {
ObjectMapper objectMapper = EncryptionModule.deserializerDecrypt(); ObjectMapper objectMapper = EncryptionModule.deserializerDecrypt();
// 指定序列化输入的类型 // 指定序列化输入的类型
@ -72,19 +72,19 @@ public class EiamGeoLocationConfiguration {
GeoLocationProviderConfig.class); GeoLocationProviderConfig.class);
// maxmind // maxmind
if (MAXMIND.equals(provider.getProvider())) { if (MAXMIND.equals(provider.getProvider())) {
return new MaxmindGeoLocationServiceImpl( return new MaxmindGeoLocationParserImpl(
(MaxmindProviderConfig) provider.getConfig(), restTemplate); (MaxmindProviderConfig) provider.getConfig(), restTemplate);
} }
// ip2region // ip2region
if (IP2REGION.equals(provider.getProvider())) { if (IP2REGION.equals(provider.getProvider())) {
return new Ip2regionGeoLocationServiceImpl(); return new Ip2regionGeoLocationParserImpl();
} }
} }
//没有数据默认使用 ip2region //没有数据默认使用 ip2region
return new Ip2regionGeoLocationServiceImpl(); return new Ip2regionGeoLocationParserImpl();
} catch (IOException e) { } catch (IOException e) {
logger.error("Create geo location Exception: {}", e.getMessage(), e); logger.error("Create geo location Exception: {}", e.getMessage(), e);
} }
return new NoneGeoLocationServiceImpl(); return new NoneGeoLocationParserImpl();
} }
} }

View File

@ -23,7 +23,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import cn.topiam.employee.common.constant.ConfigBeanNameConstants; import cn.topiam.employee.common.constant.ConfigBeanNameConstants;
import cn.topiam.employee.common.entity.account.UserEntity;
import cn.topiam.employee.common.repository.account.UserHistoryPasswordRepository; import cn.topiam.employee.common.repository.account.UserHistoryPasswordRepository;
import cn.topiam.employee.common.repository.account.UserRepository; import cn.topiam.employee.common.repository.account.UserRepository;
import cn.topiam.employee.common.repository.setting.SettingRepository; import cn.topiam.employee.common.repository.setting.SettingRepository;
@ -54,11 +53,11 @@ public class EiamPasswordConfiguration {
*/ */
@Bean(ConfigBeanNameConstants.DEFAULT_PASSWORD_POLICY_MANAGER) @Bean(ConfigBeanNameConstants.DEFAULT_PASSWORD_POLICY_MANAGER)
@RefreshScope @RefreshScope
public PasswordPolicyManager<UserEntity> passwordPolicyManager(UserRepository userRepository, public PasswordPolicyManager passwordPolicyManager(UserRepository userRepository,
UserHistoryPasswordRepository userHistoryPasswordRepository, UserHistoryPasswordRepository userHistoryPasswordRepository,
SettingRepository settingRepository, SettingRepository settingRepository,
PasswordWeakLib passwordWeakLib, PasswordWeakLib passwordWeakLib,
PasswordEncoder passwordEncoder) { PasswordEncoder passwordEncoder) {
return new DefaultPasswordPolicyManager(userRepository, userHistoryPasswordRepository, return new DefaultPasswordPolicyManager(userRepository, userHistoryPasswordRepository,
settingRepository, passwordWeakLib, passwordEncoder); settingRepository, passwordWeakLib, passwordEncoder);
} }

View File

@ -23,6 +23,7 @@ import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort; import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder;
import cn.topiam.employee.common.entity.account.UserEntity; import cn.topiam.employee.common.entity.account.UserEntity;
@ -46,7 +47,7 @@ import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIE
* @author TopIAM * @author TopIAM
* Created by support@topiam.cn on 2022/4/17 22:21 * Created by support@topiam.cn on 2022/4/17 22:21
*/ */
public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserEntity> { public class DefaultPasswordPolicyManager implements PasswordPolicyManager {
public DefaultPasswordPolicyManager(UserRepository userRepository, public DefaultPasswordPolicyManager(UserRepository userRepository,
UserHistoryPasswordRepository userHistoryPasswordRepository, UserHistoryPasswordRepository userHistoryPasswordRepository,
@ -71,19 +72,20 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
/** /**
* *
* *
* @param userId {@link Long} ID * @param principal {@link Long}
* @param password {@link String} * @param password {@link String}
*/ */
@Override @Override
public void validate(UserEntity userId, String password) { public void validate(@NonNull Object principal, String password) {
List<PasswordValidator> validators = new ArrayList<>(providers); if (principal instanceof UserEntity) {
if (userId.getId() != null) { String userId = ((UserEntity) principal).getId();
List<PasswordValidator> validators = new ArrayList<>(providers);
//@formatter:off //@formatter:off
validators.add(getPasswordIncludeUserInfoValidator(userId.getId())); validators.add(getPasswordIncludeUserInfoValidator(userId));
validators.add(getHistoryPasswordValidator(String.valueOf(userId.getId()))); validators.add(getHistoryPasswordValidator(userId));
//@formatter:on //@formatter:on
validators.forEach(passwordValidator -> passwordValidator.validate(password));
} }
validators.forEach(passwordValidator -> passwordValidator.validate(password));
} }
/** /**
@ -104,6 +106,7 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
//@formatter:off //@formatter:off
UserEntity user = optionalUser.get(); UserEntity user = optionalUser.get();
return new PasswordIncludeUserInfoValidator(user.getFullName(), user.getNickName(), user.getUsername(), user.getPhone(), user.getEmail()); return new PasswordIncludeUserInfoValidator(user.getFullName(), user.getNickName(), user.getUsername(), user.getPhone(), user.getEmail());
//@formatter:on
} }
} }
return new PasswordIncludeUserInfoValidator(false); return new PasswordIncludeUserInfoValidator(false);
@ -115,25 +118,30 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
* @return {@link HistoryPasswordValidator} * @return {@link HistoryPasswordValidator}
*/ */
private HistoryPasswordValidator getHistoryPasswordValidator(String userId) { private HistoryPasswordValidator getHistoryPasswordValidator(String userId) {
SettingEntity historyCipherCheck = settingRepository.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_HISTORY_PASSWORD_CHECK); SettingEntity historyCipherCheck = settingRepository
.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_HISTORY_PASSWORD_CHECK);
boolean enabled = Objects.isNull(historyCipherCheck) boolean enabled = Objects.isNull(historyCipherCheck)
? Boolean.parseBoolean(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_HISTORY_PASSWORD_CHECK)) ? Boolean.parseBoolean(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: Boolean.parseBoolean(historyCipherCheck.getValue()); .get(PASSWORD_POLICY_HISTORY_PASSWORD_CHECK))
: Boolean.parseBoolean(historyCipherCheck.getValue());
if (enabled) { if (enabled) {
SettingEntity historyCipherCheckCount = settingRepository.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_HISTORY_PASSWORD_CHECK_COUNT); SettingEntity historyCipherCheckCount = settingRepository.findByName(
PasswordPolicySettingConstants.PASSWORD_POLICY_HISTORY_PASSWORD_CHECK_COUNT);
Integer count = Objects.isNull(historyCipherCheckCount) Integer count = Objects.isNull(historyCipherCheckCount)
? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_HISTORY_PASSWORD_CHECK_COUNT)) ? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: Integer.valueOf(historyCipherCheckCount.getValue()); .get(PASSWORD_POLICY_HISTORY_PASSWORD_CHECK_COUNT))
: Integer.valueOf(historyCipherCheckCount.getValue());
Page<UserHistoryPasswordEntity> entities = userHistoryPasswordRepository.findAll( Page<UserHistoryPasswordEntity> entities = userHistoryPasswordRepository.findAll(
Example.of(new UserHistoryPasswordEntity().setUserId(userId)), Example.of(new UserHistoryPasswordEntity().setUserId(userId)),
PageRequest.of(0, count, Sort.by(Sort.Direction.DESC, LAST_MODIFIED_TIME))); PageRequest.of(0, count, Sort.by(Sort.Direction.DESC, LAST_MODIFIED_TIME)));
//构建历史密码验证器 //构建历史密码验证器
new HistoryPasswordValidator(entities.getContent().stream().map(UserHistoryPasswordEntity::getPassword).toList(), passwordEncoder); return new HistoryPasswordValidator(
entities.getContent().stream().map(UserHistoryPasswordEntity::getPassword).toList(),
passwordEncoder);
} }
return new HistoryPasswordValidator(false); return new HistoryPasswordValidator(false);
} }
/** /**
* *
* *
@ -142,16 +150,18 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
private PasswordLengthValidator getPasswordLengthValidator() { private PasswordLengthValidator getPasswordLengthValidator() {
//最小长度 //最小长度
SettingEntity leastLengthEntity = settingRepository SettingEntity leastLengthEntity = settingRepository
.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_LEAST_LENGTH); .findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_LEAST_LENGTH);
Integer leastLength = Objects.isNull(leastLengthEntity) Integer leastLength = Objects.isNull(leastLengthEntity)
? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_LEAST_LENGTH)) ? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: Integer.valueOf(leastLengthEntity.getValue()); .get(PASSWORD_POLICY_LEAST_LENGTH))
: Integer.valueOf(leastLengthEntity.getValue());
//最大长度 //最大长度
SettingEntity biggestLengthEntity = settingRepository SettingEntity biggestLengthEntity = settingRepository
.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_BIGGEST_LENGTH); .findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_BIGGEST_LENGTH);
Integer biggestLength = Objects.isNull(biggestLengthEntity) Integer biggestLength = Objects.isNull(biggestLengthEntity)
? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_BIGGEST_LENGTH)) ? Integer.valueOf(PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: Integer.valueOf(biggestLengthEntity.getValue()); .get(PASSWORD_POLICY_BIGGEST_LENGTH))
: Integer.valueOf(biggestLengthEntity.getValue());
return new PasswordLengthValidator(leastLength, biggestLength); return new PasswordLengthValidator(leastLength, biggestLength);
} }
@ -163,8 +173,8 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
private PasswordComplexityRuleValidator getPasswordComplexityRuleValidator() { private PasswordComplexityRuleValidator getPasswordComplexityRuleValidator() {
SettingEntity setting = settingRepository.findByName(PASSWORD_POLICY_COMPLEXITY); SettingEntity setting = settingRepository.findByName(PASSWORD_POLICY_COMPLEXITY);
String complexityRule = Objects.isNull(setting) String complexityRule = Objects.isNull(setting)
? PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_COMPLEXITY) ? PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_COMPLEXITY)
: setting.getValue(); : setting.getValue();
PasswordComplexityRule rule = PasswordComplexityRule.getType(complexityRule); PasswordComplexityRule rule = PasswordComplexityRule.getType(complexityRule);
return new PasswordComplexityRuleValidator(rule); return new PasswordComplexityRuleValidator(rule);
} }
@ -175,14 +185,17 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
* @return {@link WeakPasswordValidator} * @return {@link WeakPasswordValidator}
*/ */
private WeakPasswordValidator getWeakPasswordValidator() { private WeakPasswordValidator getWeakPasswordValidator() {
SettingEntity setting = settingRepository.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_WEAK_PASSWORD_CHECK); SettingEntity setting = settingRepository
.findByName(PasswordPolicySettingConstants.PASSWORD_POLICY_WEAK_PASSWORD_CHECK);
String enable = Objects.isNull(setting) String enable = Objects.isNull(setting)
? PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_WEAK_PASSWORD_CHECK) ? PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: setting.getValue(); .get(PASSWORD_POLICY_WEAK_PASSWORD_CHECK)
: setting.getValue();
if (Boolean.parseBoolean(enable)) { if (Boolean.parseBoolean(enable)) {
ArrayList<String> list = new ArrayList<>(); ArrayList<String> list = new ArrayList<>();
//自定义弱密码 //自定义弱密码
SettingEntity customWeakCipher = settingRepository.findByName(PASSWORD_POLICY_CUSTOM_WEAK_PASSWORD); SettingEntity customWeakCipher = settingRepository
.findByName(PASSWORD_POLICY_CUSTOM_WEAK_PASSWORD);
if (!Objects.isNull(customWeakCipher)) { if (!Objects.isNull(customWeakCipher)) {
list.addAll(Arrays.asList(customWeakCipher.getValue().split("\n"))); list.addAll(Arrays.asList(customWeakCipher.getValue().split("\n")));
} }
@ -194,6 +207,22 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
return new WeakPasswordValidator(false); return new WeakPasswordValidator(false);
} }
/**
*
*
* @param userId {@link Long} ID
* @param password {@link String}
*/
@Override
public void validate(@NonNull String userId, String password) {
List<PasswordValidator> validators = new ArrayList<>(providers);
//@formatter:off
validators.add(getPasswordIncludeUserInfoValidator(userId));
validators.add(getHistoryPasswordValidator(userId));
//@formatter:on
validators.forEach(passwordValidator -> passwordValidator.validate(password));
}
/** /**
* *
* *
@ -202,8 +231,9 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
private PasswordContinuousSameCharValidator getPasswordContinuousSameCharValidator() { private PasswordContinuousSameCharValidator getPasswordContinuousSameCharValidator() {
SettingEntity setting = settingRepository.findByName(PASSWORD_POLICY_NOT_SAME_CHARS); SettingEntity setting = settingRepository.findByName(PASSWORD_POLICY_NOT_SAME_CHARS);
String rule = Objects.isNull(setting) String rule = Objects.isNull(setting)
? PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_NOT_SAME_CHARS) ? PasswordPolicySettingConstants.PASSWORD_POLICY_DEFAULT_SETTINGS
: setting.getValue(); .get(PASSWORD_POLICY_NOT_SAME_CHARS)
: setting.getValue();
return new PasswordContinuousSameCharValidator(Integer.valueOf(rule)); return new PasswordContinuousSameCharValidator(Integer.valueOf(rule));
} }
@ -213,21 +243,22 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
* @return {@link PasswordIllegalSequenceValidator} * @return {@link PasswordIllegalSequenceValidator}
*/ */
private PasswordIllegalSequenceValidator getPasswordIllegalSequenceValidator() { private PasswordIllegalSequenceValidator getPasswordIllegalSequenceValidator() {
SettingEntity setting = settingRepository.findByName(PASSWORD_POLICY_ILLEGAL_SEQUENCE_CHECK); SettingEntity setting = settingRepository
.findByName(PASSWORD_POLICY_ILLEGAL_SEQUENCE_CHECK);
String enable = Objects.isNull(setting) String enable = Objects.isNull(setting)
? PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_ILLEGAL_SEQUENCE_CHECK) ? PASSWORD_POLICY_DEFAULT_SETTINGS.get(PASSWORD_POLICY_ILLEGAL_SEQUENCE_CHECK)
: setting.getValue(); : setting.getValue();
return new PasswordIllegalSequenceValidator(Boolean.parseBoolean(enable)); return new PasswordIllegalSequenceValidator(Boolean.parseBoolean(enable));
} }
/** /**
* *
*/ */
private final List<PasswordValidator> providers; private final List<PasswordValidator> providers;
/** /**
* *
*/ */
private final UserRepository userRepository; private final UserRepository userRepository;
/** /**
* *
*/ */
@ -235,13 +266,13 @@ public class DefaultPasswordPolicyManager implements PasswordPolicyManager<UserE
/** /**
* *
*/ */
private final SettingRepository settingRepository; private final SettingRepository settingRepository;
/** /**
* *
*/ */
private final PasswordWeakLib passwordWeakLib; private final PasswordWeakLib passwordWeakLib;
/** /**
* PasswordEncoder * PasswordEncoder
*/ */
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
} }

View File

@ -28,6 +28,7 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import cn.topiam.employee.openapi.constant.OpenApiStatus; import cn.topiam.employee.openapi.constant.OpenApiStatus;
import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint; import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import lombok.Data; import lombok.Data;
@ -43,6 +44,10 @@ import jakarta.servlet.http.HttpServletResponse;
*/ */
public final class AccessTokenAuthenticationEntryPoint extends AbstractAuthenticationEntryPoint { public final class AccessTokenAuthenticationEntryPoint extends AbstractAuthenticationEntryPoint {
public AccessTokenAuthenticationEntryPoint(UserAgentParser userAgentParser) {
super(userAgentParser);
}
/** /**
* Collect error details from the provided parameters and format according to RFC * Collect error details from the provided parameters and format according to RFC
* 6750, specifically {@code error}, {@code error_description}, {@code error_uri}, and * 6750, specifically {@code error}, {@code error_description}, {@code error_uri}, and

View File

@ -23,7 +23,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import cn.topiam.employee.EiamOpenApiApplication; import cn.topiam.employee.EiamOpenApiApplication;
import cn.topiam.employee.support.util.AppVersionUtils; import cn.topiam.employee.support.util.VersionUtils;
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.OpenAPI;
import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Contact;
@ -71,7 +71,7 @@ public class OpenApiConfiguration {
//内容 //内容
.contact(contact) .contact(contact)
//版本 //版本
.version(AppVersionUtils.getVersion(EiamOpenApiApplication.class)); .version(VersionUtils.getVersion(EiamOpenApiApplication.class));
} }
@Bean @Bean

View File

@ -34,6 +34,7 @@ import cn.topiam.employee.openapi.authorization.AccessTokenAuthenticationFilter;
import cn.topiam.employee.openapi.authorization.AccessTokenAuthenticationProvider; import cn.topiam.employee.openapi.authorization.AccessTokenAuthenticationProvider;
import cn.topiam.employee.openapi.authorization.store.AccessTokenStore; import cn.topiam.employee.openapi.authorization.store.AccessTokenStore;
import cn.topiam.employee.openapi.authorization.store.RedisAccessTokenStore; import cn.topiam.employee.openapi.authorization.store.RedisAccessTokenStore;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.DEFAULT_SECURITY_FILTER_CHAIN; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.DEFAULT_SECURITY_FILTER_CHAIN;
import static cn.topiam.employee.openapi.constant.OpenApiV1Constants.AUTH_PATH; import static cn.topiam.employee.openapi.constant.OpenApiV1Constants.AUTH_PATH;
import static cn.topiam.employee.openapi.constant.OpenApiV1Constants.OPEN_API_V1_PATH; import static cn.topiam.employee.openapi.constant.OpenApiV1Constants.OPEN_API_V1_PATH;
@ -74,7 +75,7 @@ public class OpenApiSecurityConfiguration {
//关闭 session //关闭 session
http.sessionManagement(httpSecuritySessionManagementConfigurer -> httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); http.sessionManagement(httpSecuritySessionManagementConfigurer -> httpSecuritySessionManagementConfigurer.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
//异常处理器 //异常处理器
http.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(new AccessTokenAuthenticationEntryPoint())); http.exceptionHandling(httpSecurityExceptionHandlingConfigurer -> httpSecurityExceptionHandlingConfigurer.authenticationEntryPoint(new AccessTokenAuthenticationEntryPoint(userAgentParser)));
http.addFilterBefore(new AccessTokenAuthenticationFilter(providerManager),BasicAuthenticationFilter.class); http.addFilterBefore(new AccessTokenAuthenticationFilter(providerManager),BasicAuthenticationFilter.class);
return http.build(); return http.build();
//@formatter:on //@formatter:on
@ -90,4 +91,11 @@ public class OpenApiSecurityConfiguration {
public AccessTokenStore tokenStore(RedisTemplate<Object, Object> redisTemplate) { public AccessTokenStore tokenStore(RedisTemplate<Object, Object> redisTemplate) {
return new RedisAccessTokenStore(redisTemplate); return new RedisAccessTokenStore(redisTemplate);
} }
private final UserAgentParser userAgentParser;
public OpenApiSecurityConfiguration(UserAgentParser userAgentParser) {
this.userAgentParser = userAgentParser;
}
} }

View File

@ -37,9 +37,9 @@ import cn.topiam.employee.openapi.pojo.update.UserUpdateParam;
import cn.topiam.employee.support.context.ApplicationContextService; import cn.topiam.employee.support.context.ApplicationContextService;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.security.userdetails.DataOrigin; import cn.topiam.employee.support.security.userdetails.DataOrigin;
import static cn.topiam.employee.support.util.ImageAvatarUtils.getRandomAvatar; import static cn.topiam.employee.support.util.AvatarUtils.getRandomAvatar;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneAreaCode; import static cn.topiam.employee.support.util.PhoneUtils.getPhoneAreaCode;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.getPhoneNumber;
/** /**
* *

View File

@ -28,8 +28,8 @@ import cn.topiam.employee.openapi.common.OpenApiResponse;
import cn.topiam.employee.openapi.pojo.result.AppAccountListResult; import cn.topiam.employee.openapi.pojo.result.AppAccountListResult;
import cn.topiam.employee.openapi.pojo.save.AppAccountCreateParam; import cn.topiam.employee.openapi.pojo.save.AppAccountCreateParam;
import cn.topiam.employee.openapi.service.AppAccountService; import cn.topiam.employee.openapi.service.AppAccountService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;

View File

@ -31,8 +31,8 @@ import cn.topiam.employee.openapi.pojo.result.OrganizationResult;
import cn.topiam.employee.openapi.pojo.save.OrganizationCreateParam; import cn.topiam.employee.openapi.pojo.save.OrganizationCreateParam;
import cn.topiam.employee.openapi.pojo.update.OrganizationUpdateParam; import cn.topiam.employee.openapi.pojo.update.OrganizationUpdateParam;
import cn.topiam.employee.openapi.service.OrganizationService; import cn.topiam.employee.openapi.service.OrganizationService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;

View File

@ -31,8 +31,8 @@ import cn.topiam.employee.openapi.pojo.result.UserResult;
import cn.topiam.employee.openapi.pojo.save.UserCreateParam; import cn.topiam.employee.openapi.pojo.save.UserCreateParam;
import cn.topiam.employee.openapi.pojo.update.UserUpdateParam; import cn.topiam.employee.openapi.pojo.update.UserUpdateParam;
import cn.topiam.employee.openapi.service.UserService; import cn.topiam.employee.openapi.service.UserService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.repository.page.domain.Page; import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;

View File

@ -59,8 +59,7 @@ import cn.topiam.employee.support.repository.page.domain.Page;
import cn.topiam.employee.support.repository.page.domain.PageModel; import cn.topiam.employee.support.repository.page.domain.PageModel;
import cn.topiam.employee.support.security.password.PasswordPolicyManager; import cn.topiam.employee.support.security.password.PasswordPolicyManager;
import cn.topiam.employee.support.util.BeanUtils; import cn.topiam.employee.support.util.BeanUtils;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import cn.topiam.employee.support.validation.annotation.ValidationPhone;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.topiam.employee.audit.enums.TargetType.USER; import static cn.topiam.employee.audit.enums.TargetType.USER;
@ -68,7 +67,8 @@ import static cn.topiam.employee.audit.enums.TargetType.USER_DETAIL;
import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME; import static cn.topiam.employee.core.message.sms.SmsMsgEventPublish.USERNAME;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
import static cn.topiam.employee.support.util.PhoneNumberUtils.getPhoneNumber; import static cn.topiam.employee.support.util.PhoneUtils.PHONE_REGEXP;
import static cn.topiam.employee.support.util.PhoneUtils.getPhoneNumber;
/** /**
* <p> * <p>
@ -128,7 +128,7 @@ public class UserServiceImpl implements UserService {
} }
//手机号 //手机号
if (StringUtils.isNotEmpty(param.getPhone())) { if (StringUtils.isNotEmpty(param.getPhone())) {
if (!getPhoneNumber(param.getPhone()).matches(ValidationPhone.PHONE_REGEXP)) { if (!getPhoneNumber(param.getPhone()).matches(PHONE_REGEXP)) {
throw new OpenApiException(OpenApiStatus.MOBILE_NOT_VALID); throw new OpenApiException(OpenApiStatus.MOBILE_NOT_VALID);
} }
Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), null); Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), null);
@ -206,8 +206,8 @@ public class UserServiceImpl implements UserService {
detail.orElse(null)); detail.orElse(null));
if (Objects.nonNull(userEntity) && StringUtils.isNotEmpty(userEntity.getPhone())) { if (Objects.nonNull(userEntity) && StringUtils.isNotEmpty(userEntity.getPhone())) {
StringBuilder phoneAreaCode = new StringBuilder( StringBuilder phoneAreaCode = new StringBuilder(
userEntity.getPhoneAreaCode().replace(PhoneNumberUtils.PLUS_SIGN, "")); userEntity.getPhoneAreaCode().replace(PhoneUtils.PLUS_SIGN, ""));
phoneAreaCode.insert(0, PhoneNumberUtils.PLUS_SIGN); phoneAreaCode.insert(0, PhoneUtils.PLUS_SIGN);
userResult.setPhone(phoneAreaCode + userEntity.getPhone()); userResult.setPhone(phoneAreaCode + userEntity.getPhone());
} }
return userResult; return userResult;
@ -223,7 +223,7 @@ public class UserServiceImpl implements UserService {
public void updateUser(UserUpdateParam param) { public void updateUser(UserUpdateParam param) {
if (StringUtils.isNotBlank(param.getPhone())) { if (StringUtils.isNotBlank(param.getPhone())) {
String phoneNumber = getPhoneNumber(param.getPhone()); String phoneNumber = getPhoneNumber(param.getPhone());
if (!phoneNumber.matches(ValidationPhone.PHONE_REGEXP)) { if (!phoneNumber.matches(PHONE_REGEXP)) {
throw new OpenApiException(OpenApiStatus.MOBILE_NOT_VALID); throw new OpenApiException(OpenApiStatus.MOBILE_NOT_VALID);
} }
Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(), Boolean validityPhone = userParamCheck(CheckValidityType.PHONE, param.getPhone(),
@ -342,7 +342,7 @@ public class UserServiceImpl implements UserService {
if (CheckValidityType.PHONE.equals(type)) { if (CheckValidityType.PHONE.equals(type)) {
try { try {
//手机号未修改 //手机号未修改
if (StringUtils.equals(value.replace(PhoneNumberUtils.PLUS_SIGN, ""), if (StringUtils.equals(value.replace(PhoneUtils.PLUS_SIGN, ""),
entity.getPhoneAreaCode() + entity.getPhone())) { entity.getPhoneAreaCode() + entity.getPhone())) {
return true; return true;
} }
@ -377,42 +377,42 @@ public class UserServiceImpl implements UserService {
/** /**
* *
*/ */
private final UserConverter userConverter; private final UserConverter userConverter;
/** /**
* UserRepository * UserRepository
*/ */
private final UserRepository userRepository; private final UserRepository userRepository;
/** /**
* *
*/ */
private final OrganizationMemberRepository organizationMemberRepository; private final OrganizationMemberRepository organizationMemberRepository;
/** /**
* *
*/ */
private final UserGroupMemberRepository userGroupMemberRepository; private final UserGroupMemberRepository userGroupMemberRepository;
/** /**
* Repository * Repository
*/ */
private final UserDetailRepository userDetailsRepository; private final UserDetailRepository userDetailsRepository;
/** /**
* *
*/ */
private final MailMsgEventPublish mailMsgEventPublish; private final MailMsgEventPublish mailMsgEventPublish;
/** /**
* *
*/ */
private final SmsMsgEventPublish smsMsgEventPublish; private final SmsMsgEventPublish smsMsgEventPublish;
/** /**
* PasswordPolicyManager * PasswordPolicyManager
*/ */
private final PasswordPolicyManager<UserEntity> passwordPolicyManager; private final PasswordPolicyManager passwordPolicyManager;
public UserServiceImpl(UserConverter userConverter, UserRepository userRepository, public UserServiceImpl(UserConverter userConverter, UserRepository userRepository,
OrganizationMemberRepository organizationMemberRepository, OrganizationMemberRepository organizationMemberRepository,
@ -420,7 +420,7 @@ public class UserServiceImpl implements UserService {
UserDetailRepository userDetailsRepository, UserDetailRepository userDetailsRepository,
MailMsgEventPublish mailMsgEventPublish, MailMsgEventPublish mailMsgEventPublish,
SmsMsgEventPublish smsMsgEventPublish, SmsMsgEventPublish smsMsgEventPublish,
PasswordPolicyManager<UserEntity> passwordPolicyManager) { PasswordPolicyManager passwordPolicyManager) {
this.userConverter = userConverter; this.userConverter = userConverter;
this.userRepository = userRepository; this.userRepository = userRepository;
this.organizationMemberRepository = organizationMemberRepository; this.organizationMemberRepository = organizationMemberRepository;

View File

@ -28,6 +28,7 @@ import cn.topiam.employee.core.context.ContextService;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint; import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -86,4 +87,8 @@ public class PortalAuthenticationEntryPoint extends AbstractAuthenticationEntryP
response.sendRedirect(ContextService.getPortalLoginUrl()); response.sendRedirect(ContextService.getPortalLoginUrl());
} }
} }
public PortalAuthenticationEntryPoint(UserAgentParser userAgentParser) {
super(userAgentParser);
}
} }

View File

@ -61,7 +61,7 @@ import static cn.topiam.employee.core.context.ContextService.getPortalPublicBase
import static cn.topiam.employee.support.constant.EiamConstants.CAPTCHA_CODE_SESSION; import static cn.topiam.employee.support.constant.EiamConstants.CAPTCHA_CODE_SESSION;
import static cn.topiam.employee.support.context.ServletContextService.isHtmlRequest; import static cn.topiam.employee.support.context.ServletContextService.isHtmlRequest;
import static cn.topiam.employee.support.security.authentication.AuthenticationProvider.USERNAME_PASSWORD; import static cn.topiam.employee.support.security.authentication.AuthenticationProvider.USERNAME_PASSWORD;
import static cn.topiam.employee.support.security.savedredirect.JumpController.JUMP_PATH; import static cn.topiam.employee.support.security.savedredirect.JumpConstants.JUMP_PATH;
/** /**
* *

View File

@ -22,7 +22,7 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment; import org.springframework.core.env.Environment;
import cn.topiam.employee.EiamPortalApplication; import cn.topiam.employee.EiamPortalApplication;
import cn.topiam.employee.support.util.AppVersionUtils; import cn.topiam.employee.support.util.VersionUtils;
import io.swagger.v3.oas.models.Components; import io.swagger.v3.oas.models.Components;
import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.OpenAPI;
@ -59,7 +59,7 @@ public class PortalApiConfiguration {
//内容 //内容
.contact(contact) .contact(contact)
//版本 //版本
.version(AppVersionUtils.getVersion(EiamPortalApplication.class)); .version(VersionUtils.getVersion(EiamPortalApplication.class));
} }
/** /**

View File

@ -48,6 +48,7 @@ import cn.topiam.employee.core.setting.SecuritySettingConstants;
import cn.topiam.employee.portal.authentication.*; import cn.topiam.employee.portal.authentication.*;
import cn.topiam.employee.support.redis.KeyStringRedisSerializer; import cn.topiam.employee.support.redis.KeyStringRedisSerializer;
import cn.topiam.employee.support.security.csrf.SpaCsrfTokenRequestHandler; import cn.topiam.employee.support.security.csrf.SpaCsrfTokenRequestHandler;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static org.springframework.security.web.header.writers.XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK; import static org.springframework.security.web.header.writers.XXssProtectionHeaderWriter.HeaderValue.ENABLED_MODE_BLOCK;
import static org.springframework.web.cors.CorsConfiguration.ALL; import static org.springframework.web.cors.CorsConfiguration.ALL;
@ -150,7 +151,8 @@ public class AbstractSecurityConfiguration {
*/ */
public Customizer<ExceptionHandlingConfigurer<HttpSecurity>> withExceptionConfigurerDefaults() { public Customizer<ExceptionHandlingConfigurer<HttpSecurity>> withExceptionConfigurerDefaults() {
return configurer -> { return configurer -> {
configurer.authenticationEntryPoint(new PortalAuthenticationEntryPoint()); configurer
.authenticationEntryPoint(new PortalAuthenticationEntryPoint(userAgentParser));
configurer.accessDeniedHandler(new PortalAccessDeniedHandler()); configurer.accessDeniedHandler(new PortalAccessDeniedHandler());
configurer configurer
.withObjectPostProcessor(new ObjectPostProcessor<ExceptionTranslationFilter>() { .withObjectPostProcessor(new ObjectPostProcessor<ExceptionTranslationFilter>() {
@ -219,11 +221,15 @@ public class AbstractSecurityConfiguration {
}; };
} }
private final UserAgentParser userAgentParser;
private final SettingRepository settingRepository; private final SettingRepository settingRepository;
public AbstractSecurityConfiguration(SettingRepository settingRepository) { public AbstractSecurityConfiguration(UserAgentParser userAgentParser,
SettingRepository settingRepository) {
Assert.notNull(settingRepository, "The userAgentParser cannot be null");
Assert.notNull(settingRepository, "The settingRepository cannot be null"); Assert.notNull(settingRepository, "The settingRepository cannot be null");
this.settingRepository = settingRepository; this.settingRepository = settingRepository;
this.userAgentParser = userAgentParser;
} }
} }

View File

@ -41,6 +41,7 @@ import cn.topiam.employee.protocol.form.RedisFormAuthorizationService;
import cn.topiam.employee.protocol.form.authentication.FormAuthenticationFailureEventListener; import cn.topiam.employee.protocol.form.authentication.FormAuthenticationFailureEventListener;
import cn.topiam.employee.protocol.form.authentication.FormAuthenticationSuccessEventListener; import cn.topiam.employee.protocol.form.authentication.FormAuthenticationSuccessEventListener;
import cn.topiam.employee.protocol.form.configurers.FormAuthorizationServerConfigurer; import cn.topiam.employee.protocol.form.configurers.FormAuthorizationServerConfigurer;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static org.springframework.security.config.http.SessionCreationPolicy.NEVER; import static org.springframework.security.config.http.SessionCreationPolicy.NEVER;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.FORM_PROTOCOL_SECURITY_FILTER_CHAIN; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.FORM_PROTOCOL_SECURITY_FILTER_CHAIN;
@ -54,10 +55,6 @@ import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.FORM_PR
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class FormProtocolSecurityConfiguration extends AbstractSecurityConfiguration { public class FormProtocolSecurityConfiguration extends AbstractSecurityConfiguration {
public FormProtocolSecurityConfiguration(SettingRepository settingRepository) {
super(settingRepository);
}
/** /**
* FormProtocolSecurityFilterChain * FormProtocolSecurityFilterChain
* *
@ -71,7 +68,7 @@ public class FormProtocolSecurityConfiguration extends AbstractSecurityConfigura
//@formatter:off //@formatter:off
httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null); httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null);
//Form IDP 配置 //Form IDP 配置
FormAuthorizationServerConfigurer serverConfigurer = new FormAuthorizationServerConfigurer(); FormAuthorizationServerConfigurer serverConfigurer = new FormAuthorizationServerConfigurer(userAgentParser);
RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher(); RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher();
httpSecurity.securityMatcher(endpointsMatcher) httpSecurity.securityMatcher(endpointsMatcher)
.authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated()) .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
@ -123,4 +120,12 @@ public class FormProtocolSecurityConfiguration extends AbstractSecurityConfigura
applicationServiceLoader); applicationServiceLoader);
} }
public FormProtocolSecurityConfiguration(SettingRepository settingRepository,
UserAgentParser userAgentParser) {
super(userAgentParser, settingRepository);
this.userAgentParser = userAgentParser;
}
private final UserAgentParser userAgentParser;
} }

View File

@ -41,6 +41,7 @@ import cn.topiam.employee.protocol.jwt.RedisJwtAuthorizationService;
import cn.topiam.employee.protocol.jwt.authentication.JwtAuthenticationFailureEventListener; import cn.topiam.employee.protocol.jwt.authentication.JwtAuthenticationFailureEventListener;
import cn.topiam.employee.protocol.jwt.authentication.JwtAuthenticationSuccessEventListener; import cn.topiam.employee.protocol.jwt.authentication.JwtAuthenticationSuccessEventListener;
import cn.topiam.employee.protocol.jwt.configurers.JwtAuthorizationServerConfigurer; import cn.topiam.employee.protocol.jwt.configurers.JwtAuthorizationServerConfigurer;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static org.springframework.security.config.http.SessionCreationPolicy.NEVER; import static org.springframework.security.config.http.SessionCreationPolicy.NEVER;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.JWT_PROTOCOL_SECURITY_FILTER_CHAIN; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.JWT_PROTOCOL_SECURITY_FILTER_CHAIN;
@ -54,10 +55,6 @@ import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.JWT_PRO
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class JwtProtocolSecurityConfiguration extends AbstractSecurityConfiguration { public class JwtProtocolSecurityConfiguration extends AbstractSecurityConfiguration {
public JwtProtocolSecurityConfiguration(SettingRepository settingRepository) {
super(settingRepository);
}
/** /**
* JwtProtocolSecurityFilterChain * JwtProtocolSecurityFilterChain
* *
@ -71,7 +68,7 @@ public class JwtProtocolSecurityConfiguration extends AbstractSecurityConfigurat
//@formatter:off //@formatter:off
httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null); httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null);
//Jwt IDP 配置 //Jwt IDP 配置
JwtAuthorizationServerConfigurer serverConfigurer = new JwtAuthorizationServerConfigurer(); JwtAuthorizationServerConfigurer serverConfigurer = new JwtAuthorizationServerConfigurer(userAgentParser);
RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher(); RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher();
httpSecurity.securityMatcher(endpointsMatcher) httpSecurity.securityMatcher(endpointsMatcher)
.authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated()) .authorizeHttpRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated())
@ -123,4 +120,12 @@ public class JwtProtocolSecurityConfiguration extends AbstractSecurityConfigurat
applicationServiceLoader); applicationServiceLoader);
} }
private final UserAgentParser userAgentParser;
public JwtProtocolSecurityConfiguration(SettingRepository settingRepository,
UserAgentParser userAgentParser) {
super(userAgentParser, settingRepository);
this.userAgentParser = userAgentParser;
}
} }

View File

@ -61,6 +61,7 @@ import cn.topiam.employee.common.repository.app.AppOidcConfigRepository;
import cn.topiam.employee.common.repository.setting.SettingRepository; import cn.topiam.employee.common.repository.setting.SettingRepository;
import cn.topiam.employee.support.jackjson.SupportJackson2Module; import cn.topiam.employee.support.jackjson.SupportJackson2Module;
import cn.topiam.employee.support.redis.KeyStringRedisSerializer; import cn.topiam.employee.support.redis.KeyStringRedisSerializer;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static org.springframework.security.config.http.SessionCreationPolicy.NEVER; import static org.springframework.security.config.http.SessionCreationPolicy.NEVER;
import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.OIDC_PROTOCOL_SECURITY_FILTER_CHAIN; import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.OIDC_PROTOCOL_SECURITY_FILTER_CHAIN;
@ -75,10 +76,6 @@ import static cn.topiam.employee.common.constant.ConfigBeanNameConstants.OIDC_PR
@Configuration(proxyBeanMethods = false) @Configuration(proxyBeanMethods = false)
public class OidcProtocolSecurityConfiguration extends AbstractSecurityConfiguration { public class OidcProtocolSecurityConfiguration extends AbstractSecurityConfiguration {
public OidcProtocolSecurityConfiguration(SettingRepository settingRepository) {
super(settingRepository);
}
/** /**
* OIDC * OIDC
* *
@ -91,7 +88,7 @@ public class OidcProtocolSecurityConfiguration extends AbstractSecurityConfigura
AccessTokenAuthenticationManagerResolver authenticationManagerResolver) throws Exception { AccessTokenAuthenticationManagerResolver authenticationManagerResolver) throws Exception {
//@formatter:off //@formatter:off
httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null); httpSecurity.getSharedObject(AuthenticationManagerBuilder.class).parentAuthenticationManager(null);
OAuth2AuthorizationServerConfigurer serverConfigurer = new OAuth2AuthorizationServerConfigurer(); OAuth2AuthorizationServerConfigurer serverConfigurer = new OAuth2AuthorizationServerConfigurer(userAgentParser);
RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher(); RequestMatcher endpointsMatcher = serverConfigurer.getEndpointsMatcher();
OrRequestMatcher requestMatcher = new OrRequestMatcher(endpointsMatcher); OrRequestMatcher requestMatcher = new OrRequestMatcher(endpointsMatcher);
httpSecurity httpSecurity
@ -245,4 +242,12 @@ public class OidcProtocolSecurityConfiguration extends AbstractSecurityConfigura
public OidcOpenApiCustomizer oidcOpenApiCustomizer() { public OidcOpenApiCustomizer oidcOpenApiCustomizer() {
return new OidcOpenApiCustomizer(); return new OidcOpenApiCustomizer();
} }
public OidcProtocolSecurityConfiguration(SettingRepository settingRepository,
UserAgentParser userAgentParser) {
super(userAgentParser, settingRepository);
this.userAgentParser = userAgentParser;
}
private final UserAgentParser userAgentParser;
} }

View File

@ -73,10 +73,11 @@ import cn.topiam.employee.core.security.password.task.impl.PasswordExpireWarnTas
import cn.topiam.employee.core.security.task.UserExpireLockTask; import cn.topiam.employee.core.security.task.UserExpireLockTask;
import cn.topiam.employee.core.security.task.UserUnlockTask; import cn.topiam.employee.core.security.task.UserUnlockTask;
import cn.topiam.employee.portal.authentication.*; import cn.topiam.employee.portal.authentication.*;
import cn.topiam.employee.support.geo.GeoLocationService; import cn.topiam.employee.support.geo.GeoLocationParser;
import cn.topiam.employee.support.jackjson.SupportJackson2Module; import cn.topiam.employee.support.jackjson.SupportJackson2Module;
import cn.topiam.employee.support.security.authentication.WebAuthenticationDetailsSource; import cn.topiam.employee.support.security.authentication.WebAuthenticationDetailsSource;
import cn.topiam.employee.support.security.configurer.FormLoginConfigurer; import cn.topiam.employee.support.security.configurer.FormLoginConfigurer;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static org.springframework.http.HttpMethod.*; import static org.springframework.http.HttpMethod.*;
import static org.springframework.security.config.Customizer.withDefaults; import static org.springframework.security.config.Customizer.withDefaults;
@ -435,12 +436,13 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration
/** /**
* WebAuthenticationDetailsSource * WebAuthenticationDetailsSource
* *
* @param geoLocationService {@link GeoLocationService} * @param geoLocationParser {@link GeoLocationParser}
* @return {@link WebAuthenticationDetailsSource} * @return {@link WebAuthenticationDetailsSource}
*/ */
@Bean @Bean
public WebAuthenticationDetailsSource authenticationDetailsSource(GeoLocationService geoLocationService) { public WebAuthenticationDetailsSource authenticationDetailsSource(GeoLocationParser geoLocationParser,
return new WebAuthenticationDetailsSource(geoLocationService); UserAgentParser userAgentParser) {
return new WebAuthenticationDetailsSource(geoLocationParser, userAgentParser);
} }
/** /**
@ -478,7 +480,8 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration
this.loader = classLoader; this.loader = classLoader;
} }
public PortalSecurityConfiguration(UserRepository userRepository, public PortalSecurityConfiguration(UserAgentParser userAgentParser,
UserRepository userRepository,
UserDetailsService userDetailsService, UserDetailsService userDetailsService,
OtpContextHelp otpContextHelp, OtpContextHelp otpContextHelp,
PasswordEncoder passwordEncoder, PasswordEncoder passwordEncoder,
@ -486,7 +489,7 @@ public class PortalSecurityConfiguration extends AbstractSecurityConfiguration
SettingRepository settingRepository, SettingRepository settingRepository,
RegisteredIdentityProviderClientRepository registeredIdentityProviderClientRepository, RegisteredIdentityProviderClientRepository registeredIdentityProviderClientRepository,
IdentityProviderAuthenticationService identityProviderAuthenticationService) { IdentityProviderAuthenticationService identityProviderAuthenticationService) {
super(settingRepository); super(userAgentParser, settingRepository);
this.userRepository = userRepository; this.userRepository = userRepository;
this.userDetailsService = userDetailsService; this.userDetailsService = userDetailsService;
this.otpContextHelp = otpContextHelp; this.otpContextHelp = otpContextHelp;

View File

@ -29,8 +29,8 @@ import cn.topiam.employee.audit.annotation.Audit;
import cn.topiam.employee.audit.event.type.EventType; import cn.topiam.employee.audit.event.type.EventType;
import cn.topiam.employee.portal.pojo.request.AppAccountRequest; import cn.topiam.employee.portal.pojo.request.AppAccountRequest;
import cn.topiam.employee.portal.service.AppAccountService; import cn.topiam.employee.portal.service.AppAccountService;
import cn.topiam.employee.support.demo.Preview;
import cn.topiam.employee.support.lock.Lock; import cn.topiam.employee.support.lock.Lock;
import cn.topiam.employee.support.preview.Preview;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;

View File

@ -28,15 +28,16 @@ import org.springframework.web.bind.annotation.RestController;
import cn.topiam.employee.common.entity.account.UserEntity; import cn.topiam.employee.common.entity.account.UserEntity;
import cn.topiam.employee.core.security.util.UserUtils; import cn.topiam.employee.core.security.util.UserUtils;
import cn.topiam.employee.support.result.ApiRestResult; import cn.topiam.employee.support.result.ApiRestResult;
import cn.topiam.employee.support.util.DesensitizationUtil;
import lombok.Data; import lombok.Data;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import io.swagger.v3.oas.annotations.media.Schema; import io.swagger.v3.oas.annotations.media.Schema;
import static cn.topiam.employee.common.constant.SessionConstants.CURRENT_USER; import static cn.topiam.employee.common.constant.SessionConstants.CURRENT_USER;
import static cn.topiam.employee.support.util.ImageAvatarUtils.bufferedImageToBase64; import static cn.topiam.employee.support.util.AvatarUtils.bufferedImageToBase64;
import static cn.topiam.employee.support.util.ImageAvatarUtils.generateAvatarImg; import static cn.topiam.employee.support.util.AvatarUtils.generateAvatarImg;
import static cn.topiam.employee.support.util.DesensitizationUtils.emailEncrypt;
import static cn.topiam.employee.support.util.DesensitizationUtils.phoneEncrypt;
/** /**
* *
@ -70,9 +71,9 @@ public class CurrentUserEndpoint {
result.setAvatar(user.getAvatar()); result.setAvatar(user.getAvatar());
} }
//邮箱 //邮箱
result.setEmail(DesensitizationUtil.emailEncrypt(user.getEmail())); result.setEmail(emailEncrypt(user.getEmail()));
//手机号 //手机号
result.setPhone(DesensitizationUtil.phoneEncrypt(user.getPhone())); result.setPhone(phoneEncrypt(user.getPhone()));
return ApiRestResult.ok(result); return ApiRestResult.ok(result);
} }

View File

@ -65,7 +65,7 @@ import cn.topiam.employee.support.security.password.exception.PasswordValidatedF
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.security.util.SecurityUtils; import cn.topiam.employee.support.security.util.SecurityUtils;
import cn.topiam.employee.support.util.BeanUtils; import cn.topiam.employee.support.util.BeanUtils;
import cn.topiam.employee.support.util.PhoneNumberUtils; import cn.topiam.employee.support.util.PhoneUtils;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
@ -77,7 +77,7 @@ import static cn.topiam.employee.support.exception.enums.ExceptionStatus.EX00010
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_BY;
import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME; import static cn.topiam.employee.support.repository.base.BaseEntity.LAST_MODIFIED_TIME;
import static cn.topiam.employee.support.util.EmailUtils.isEmailValidate; import static cn.topiam.employee.support.util.EmailUtils.isEmailValidate;
import static cn.topiam.employee.support.util.PhoneNumberUtils.isPhoneValidate; import static cn.topiam.employee.support.util.PhoneUtils.isPhoneValidate;
/** /**
* @author TopIAM * @author TopIAM
@ -263,7 +263,7 @@ public class AccountServiceImpl implements AccountService {
} else if (isPhoneValidate(recipient)) { } else if (isPhoneValidate(recipient)) {
// 验证在库中是否有手机号 // 验证在库中是否有手机号
Optional<UserEntity> optional = userRepository Optional<UserEntity> optional = userRepository
.findByPhone(PhoneNumberUtils.getPhoneNumber(recipient)); .findByPhone(PhoneUtils.getPhoneNumber(recipient));
if (optional.isPresent()) { if (optional.isPresent()) {
otpContextHelp.sendOtp(recipient, SmsType.FORGET_PASSWORD.getCode(), otpContextHelp.sendOtp(recipient, SmsType.FORGET_PASSWORD.getCode(),
MessageNoticeChannel.SMS); MessageNoticeChannel.SMS);
@ -287,7 +287,7 @@ public class AccountServiceImpl implements AccountService {
MessageNoticeChannel.MAIL, recipient, code); MessageNoticeChannel.MAIL, recipient, code);
} }
} else if (isPhoneValidate(recipient)) { } else if (isPhoneValidate(recipient)) {
optional = userRepository.findByPhone(PhoneNumberUtils.getPhoneNumber(recipient)); optional = userRepository.findByPhone(PhoneUtils.getPhoneNumber(recipient));
if (optional.isPresent()) { if (optional.isPresent()) {
checkOtp = otpContextHelp.checkOtp(SmsType.FORGET_PASSWORD.getCode(), checkOtp = otpContextHelp.checkOtp(SmsType.FORGET_PASSWORD.getCode(),
MessageNoticeChannel.SMS, recipient, code); MessageNoticeChannel.SMS, recipient, code);
@ -410,62 +410,62 @@ public class AccountServiceImpl implements AccountService {
/** /**
* Executor * Executor
*/ */
private final Executor executor; private final Executor executor;
/** /**
* AccountConverter * AccountConverter
*/ */
private final AccountConverter accountConverter; private final AccountConverter accountConverter;
/** /**
* PasswordEncoder * PasswordEncoder
*/ */
private final PasswordEncoder passwordEncoder; private final PasswordEncoder passwordEncoder;
/** /**
* UserRepository * UserRepository
*/ */
private final UserRepository userRepository; private final UserRepository userRepository;
/** /**
* Repository * Repository
*/ */
private final UserDetailRepository userDetailsRepository; private final UserDetailRepository userDetailsRepository;
/** /**
* SessionRegistry * SessionRegistry
*/ */
private final SessionRegistry sessionRegistry; private final SessionRegistry sessionRegistry;
/** /**
* OtpContextHelp * OtpContextHelp
*/ */
private final OtpContextHelp otpContextHelp; private final OtpContextHelp otpContextHelp;
/** /**
* SmsMsgEventPublish * SmsMsgEventPublish
*/ */
private final SmsMsgEventPublish smsMsgEventPublish; private final SmsMsgEventPublish smsMsgEventPublish;
/** /**
* StringRedisTemplate * StringRedisTemplate
*/ */
private final StringRedisTemplate stringRedisTemplate; private final StringRedisTemplate stringRedisTemplate;
/** /**
* PasswordPolicyManager * PasswordPolicyManager
*/ */
private final PasswordPolicyManager<UserEntity> passwordPolicyManager; private final PasswordPolicyManager passwordPolicyManager;
/** /**
* IdentityProviderRepository * IdentityProviderRepository
*/ */
private final IdentityProviderRepository identityProviderRepository; private final IdentityProviderRepository identityProviderRepository;
/** /**
* UserAuthnBindRepository * UserAuthnBindRepository
*/ */
private final UserIdpRepository userIdpRepository; private final UserIdpRepository userIdpRepository;
public AccountServiceImpl(AsyncConfigurer asyncConfigurer, AccountConverter accountConverter, public AccountServiceImpl(AsyncConfigurer asyncConfigurer, AccountConverter accountConverter,
PasswordEncoder passwordEncoder, UserRepository userRepository, PasswordEncoder passwordEncoder, UserRepository userRepository,
@ -473,7 +473,7 @@ public class AccountServiceImpl implements AccountService {
SessionRegistry sessionRegistry, OtpContextHelp otpContextHelp, SessionRegistry sessionRegistry, OtpContextHelp otpContextHelp,
SmsMsgEventPublish smsMsgEventPublish, SmsMsgEventPublish smsMsgEventPublish,
StringRedisTemplate stringRedisTemplate, StringRedisTemplate stringRedisTemplate,
PasswordPolicyManager<UserEntity> passwordPolicyManager, PasswordPolicyManager passwordPolicyManager,
IdentityProviderRepository identityProviderRepository, IdentityProviderRepository identityProviderRepository,
UserIdpRepository userIdpRepository) { UserIdpRepository userIdpRepository) {
this.executor = asyncConfigurer.getAsyncExecutor(); this.executor = asyncConfigurer.getAsyncExecutor();

View File

@ -17,13 +17,23 @@
*/ */
package cn.topiam.employee.portal.service.userdetail; package cn.topiam.employee.portal.service.userdetail;
import java.time.LocalDateTime;
import java.util.Optional;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import cn.topiam.employee.audit.context.AuditContext;
import cn.topiam.employee.audit.entity.Target;
import cn.topiam.employee.audit.enums.TargetType;
import cn.topiam.employee.common.entity.account.UserEntity; import cn.topiam.employee.common.entity.account.UserEntity;
import cn.topiam.employee.common.repository.account.UserRepository;
import cn.topiam.employee.portal.service.UserService; import cn.topiam.employee.portal.service.UserService;
import cn.topiam.employee.support.exception.TopIamException;
import cn.topiam.employee.support.security.password.exception.PasswordValidatedFailException;
import cn.topiam.employee.support.security.userdetails.UserDetails; import cn.topiam.employee.support.security.userdetails.UserDetails;
import cn.topiam.employee.support.security.userdetails.UserDetailsService; import cn.topiam.employee.support.security.userdetails.UserDetailsService;
@ -60,21 +70,99 @@ public class UserDetailsServiceImpl implements UserDetailsService {
} }
@Override @Override
public void changePassword(String username, String newPassword) { public UserDetails loadUserByPhone(String phone) throws UsernameNotFoundException {
Optional<UserEntity> optional = userRepository.findByPhone(phone);
//不存在该用户
if (optional.isEmpty()) {
logger.info("根据手机号未查询该管理员【{}】", phone);
throw new UsernameNotFoundException("用户名或密码错误");
}
return getUserDetails(optional.get());
}
@Override
public UserDetails loadUserByEmail(String email) throws UsernameNotFoundException {
Optional<UserEntity> optional = userRepository.findByEmail(email);
//不存在该用户
if (optional.isEmpty()) {
logger.info("根据邮箱未查询该管理员【{}】", email);
throw new UsernameNotFoundException("用户名或密码错误");
}
return getUserDetails(optional.get());
}
private UserDetails getUserDetails(UserEntity user) {
//锁定
if (user.isLocked()) {
logger.info("用户【{}】被锁定", user.getUsername());
}
//禁用
if (user.isDisabled()) {
logger.info("用户【{}】被禁用", user.getUsername());
}
return userService.getUserDetails(user);
}
public void forceResetUserPassword(UserEntity user, String password) {
boolean matches = passwordEncoder.matches(password, user.getPassword());
if (matches) {
logger.error("用户ID: [{}] 用户名: [{}] 新密码与旧密码相同", user.getId(), user.getUsername());
throw new PasswordValidatedFailException("新密码不允许与旧密码相同");
}
password = passwordEncoder.encode(password);
user.setPassword(password);
user.setLastUpdatePasswordTime(LocalDateTime.now());
user.setNeedChangePassword(false);
// 更新密码
userRepository.save(user);
AuditContext.setTarget(Target.builder().id(user.getId()).name(user.getUsername())
.type(TargetType.USER).build());
}
@Override
public void changePassword(String username, String newPassword) {
UserEntity user = findByUsername(username);
forceResetUserPassword(user, newPassword);
} }
@Override @Override
public void changePassword(String username, String oldPassword, String newPassword) { public void changePassword(String username, String oldPassword, String newPassword) {
UserEntity user = findByUsername(username);
boolean matches = passwordEncoder.matches(oldPassword, user.getPassword());
if (!matches) {
logger.error("用户ID: [{}] 用户名: [{}] 旧密码匹配失败", user.getId(), user.getUsername());
throw new PasswordValidatedFailException();
}
forceResetUserPassword(user, newPassword);
}
public UserEntity findByUsername(String username) {
return userRepository.findByUsername(username).orElseThrow(() -> {
AuditContext.setContent("重置密码失败,用户不存在");
logger.warn(AuditContext.getContent());
return new TopIamException("操作失败");
});
} }
/** /**
* UserService * UserService
*/ */
private final UserService userService; private final UserRepository userRepository;
public UserDetailsServiceImpl(UserService userService) { /**
* PasswordEncoder
*/
private final PasswordEncoder passwordEncoder;
/**
* UserService
*/
private final UserService userService;
public UserDetailsServiceImpl(UserRepository userRepository, PasswordEncoder passwordEncoder,
UserService userService) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
this.userService = userService; this.userService = userService;
} }
} }

View File

@ -30,6 +30,7 @@ import cn.topiam.employee.support.security.savedredirect.HttpSessionRedirectCach
import cn.topiam.employee.support.security.savedredirect.RedirectCache; import cn.topiam.employee.support.security.savedredirect.RedirectCache;
import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint; import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint;
import cn.topiam.employee.support.util.HttpResponseUtils; import cn.topiam.employee.support.util.HttpResponseUtils;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
@ -46,6 +47,10 @@ public class UnauthorizedAuthenticationEntryPoint extends AbstractAuthentication
private final Logger logger = LoggerFactory.getLogger(this.getClass()); private final Logger logger = LoggerFactory.getLogger(this.getClass());
private final RedirectCache redirectCache = new HttpSessionRedirectCache(); private final RedirectCache redirectCache = new HttpSessionRedirectCache();
public UnauthorizedAuthenticationEntryPoint(UserAgentParser userAgentParser) {
super(userAgentParser);
}
@Override @Override
public void commence(HttpServletRequest request, HttpServletResponse response, public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException { AuthenticationException authException) throws IOException {

View File

@ -33,6 +33,7 @@ import cn.topiam.employee.protocol.code.EndpointMatcher;
import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint; import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint;
import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer; import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer;
import cn.topiam.employee.protocol.form.context.FormAuthorizationServerContextFilter; import cn.topiam.employee.protocol.form.context.FormAuthorizationServerContextFilter;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader; import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader;
/** /**
@ -67,8 +68,8 @@ public final class FormAuthorizationServerConfigurer extends
httpSecurity.exceptionHandling(exceptionHandling -> { httpSecurity.exceptionHandling(exceptionHandling -> {
if (exceptionHandling != null) { if (exceptionHandling != null) {
//身份验证入口点 //身份验证入口点
exceptionHandling exceptionHandling.authenticationEntryPoint(
.authenticationEntryPoint(new UnauthorizedAuthenticationEntryPoint()); new UnauthorizedAuthenticationEntryPoint(userAgentParser));
} }
}); });
} }
@ -97,4 +98,9 @@ public final class FormAuthorizationServerConfigurer extends
return configurers; return configurers;
} }
private final UserAgentParser userAgentParser;
public FormAuthorizationServerConfigurer(UserAgentParser userAgentParser) {
this.userAgentParser = userAgentParser;
}
} }

View File

@ -33,6 +33,7 @@ import cn.topiam.employee.protocol.code.EndpointMatcher;
import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint; import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint;
import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer; import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer;
import cn.topiam.employee.protocol.jwt.context.JwtAuthorizationServerContextFilter; import cn.topiam.employee.protocol.jwt.context.JwtAuthorizationServerContextFilter;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader; import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader;
/** /**
@ -67,8 +68,8 @@ public final class JwtAuthorizationServerConfigurer extends
httpSecurity.exceptionHandling(exceptionHandling -> { httpSecurity.exceptionHandling(exceptionHandling -> {
if (exceptionHandling != null) { if (exceptionHandling != null) {
//身份验证入口点 //身份验证入口点
exceptionHandling exceptionHandling.authenticationEntryPoint(
.authenticationEntryPoint(new UnauthorizedAuthenticationEntryPoint()); new UnauthorizedAuthenticationEntryPoint(userAgentParser));
} }
}); });
@ -99,4 +100,9 @@ public final class JwtAuthorizationServerConfigurer extends
return configurers; return configurers;
} }
private final UserAgentParser userAgentParser;
public JwtAuthorizationServerConfigurer(UserAgentParser userAgentParser) {
this.userAgentParser = userAgentParser;
}
} }

View File

@ -27,6 +27,7 @@ import org.springframework.security.oauth2.core.OAuth2Error;
import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter; import org.springframework.security.oauth2.core.http.converter.OAuth2ErrorHttpMessageConverter;
import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint; import cn.topiam.employee.support.security.web.AbstractAuthenticationEntryPoint;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import jakarta.servlet.ServletException; import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
@ -43,6 +44,10 @@ import static cn.topiam.eiam.protocol.oidc.constant.OidcProtocolConstants.OIDC_E
*/ */
public class ClientAuthenticationRequiredEntryPoint extends AbstractAuthenticationEntryPoint { public class ClientAuthenticationRequiredEntryPoint extends AbstractAuthenticationEntryPoint {
public ClientAuthenticationRequiredEntryPoint(UserAgentParser userAgentParser) {
super(userAgentParser);
}
@Override @Override
public void commence(HttpServletRequest request, HttpServletResponse response, public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException, AuthenticationException authException) throws IOException,

View File

@ -52,6 +52,7 @@ import cn.topiam.employee.common.constant.ProtocolConstants;
import cn.topiam.employee.protocol.code.EndpointMatcher; import cn.topiam.employee.protocol.code.EndpointMatcher;
import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint; import cn.topiam.employee.protocol.code.UnauthorizedAuthenticationEntryPoint;
import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer; import cn.topiam.employee.protocol.code.configurer.AbstractConfigurer;
import cn.topiam.employee.support.web.useragent.UserAgentParser;
import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader; import static cn.topiam.employee.protocol.code.configurer.AuthenticationUtils.getApplicationServiceLoader;
import static cn.topiam.employee.support.security.util.HttpSecurityConfigUtils.getOptionalBean; import static cn.topiam.employee.support.security.util.HttpSecurityConfigUtils.getOptionalBean;
@ -97,10 +98,10 @@ public final class OAuth2AuthorizationServerConfigurer extends
if (exceptionHandling != null) { if (exceptionHandling != null) {
//认证端点异常 //认证端点异常
exceptionHandling.defaultAuthenticationEntryPointFor( exceptionHandling.defaultAuthenticationEntryPointFor(
new UnauthorizedAuthenticationEntryPoint(), new OrRequestMatcher( new UnauthorizedAuthenticationEntryPoint(userAgentParser), new OrRequestMatcher(
getRequestMatcher(OAuth2AuthorizationEndpointConfigurer.class))); getRequestMatcher(OAuth2AuthorizationEndpointConfigurer.class)));
exceptionHandling.defaultAuthenticationEntryPointFor( exceptionHandling.defaultAuthenticationEntryPointFor(
new ClientAuthenticationRequiredEntryPoint(), new ClientAuthenticationRequiredEntryPoint(userAgentParser),
new OrRequestMatcher(getRequestMatcher(OAuth2TokenEndpointConfigurer.class), new OrRequestMatcher(getRequestMatcher(OAuth2TokenEndpointConfigurer.class),
getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class), getRequestMatcher(OAuth2TokenIntrospectionEndpointConfigurer.class),
getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class), getRequestMatcher(OAuth2TokenRevocationEndpointConfigurer.class),
@ -200,4 +201,9 @@ public final class OAuth2AuthorizationServerConfigurer extends
return configurers; return configurers;
} }
private final UserAgentParser userAgentParser;
public OAuth2AuthorizationServerConfigurer(UserAgentParser userAgentParser) {
this.userAgentParser = userAgentParser;
}
} }

View File

@ -68,7 +68,8 @@ import cn.topiam.employee.support.trace.TraceUtils;
import cn.topiam.employee.synchronizer.task.IdentitySourceSyncTask; import cn.topiam.employee.synchronizer.task.IdentitySourceSyncTask;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix; import static cn.topiam.employee.support.constant.EiamConstants.CACHE_LOCK_KEY_PREFIX;
import static cn.topiam.employee.support.constant.EiamConstants.COLON;
import static cn.topiam.employee.synchronizer.configuration.IdentitySourceBeanUtils.getSourceBeanName; import static cn.topiam.employee.synchronizer.configuration.IdentitySourceBeanUtils.getSourceBeanName;
/** /**
@ -305,7 +306,7 @@ public class IdentitySourceBeanRegistry implements IdentitySourceEventListener {
stopWatch.start(); stopWatch.start();
log.info("[手动任务]-同步身份源[{}]数据开始", identitySource.getName()); log.info("[手动任务]-同步身份源[{}]数据开始", identitySource.getName());
TraceUtils.put(new JdkIdGenerator().generateId().toString()); TraceUtils.put(new JdkIdGenerator().generateId().toString());
RLock lock = redissonClient.getLock(getTopiamLockKeyPrefix() + id); RLock lock = redissonClient.getLock(CACHE_LOCK_KEY_PREFIX + COLON + id);
boolean tryLock = false; boolean tryLock = false;
try { try {
tryLock = lock.tryLock(1, TimeUnit.SECONDS); tryLock = lock.tryLock(1, TimeUnit.SECONDS);

View File

@ -32,7 +32,8 @@ import cn.topiam.employee.identitysource.core.IdentitySourceConfig;
import cn.topiam.employee.support.trace.TraceUtils; import cn.topiam.employee.support.trace.TraceUtils;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import static cn.topiam.employee.support.lock.LockAspect.getTopiamLockKeyPrefix; import static cn.topiam.employee.support.constant.EiamConstants.CACHE_LOCK_KEY_PREFIX;
import static cn.topiam.employee.support.constant.EiamConstants.COLON;
/** /**
* *
@ -64,7 +65,7 @@ public class IdentitySourceSyncTask implements Runnable {
logger.info("[任务触发]-同步身份源[{}]数据开始", name); logger.info("[任务触发]-同步身份源[{}]数据开始", name);
String traceId = idGenerator.generateId().toString(); String traceId = idGenerator.generateId().toString();
TraceUtils.put(traceId); TraceUtils.put(traceId);
RLock lock = redissonClient.getLock(getTopiamLockKeyPrefix() + id); RLock lock = redissonClient.getLock(CACHE_LOCK_KEY_PREFIX + COLON + id);
boolean tryLock = false; boolean tryLock = false;
try { try {
tryLock = lock.tryLock(1, TimeUnit.SECONDS); tryLock = lock.tryLock(1, TimeUnit.SECONDS);