diff --git a/cloud-auth/src/main/java/cn/sh/stc/sict/cloud/auth/handler/SictAuthenticationFailureLockEventHandler.java b/cloud-auth/src/main/java/cn/sh/stc/sict/cloud/auth/handler/SictAuthenticationFailureLockEventHandler.java index e6056d74c1d414427cc877dc898f2768afa637d4..9d297148b952661426b730617a652b0110920add 100644 --- a/cloud-auth/src/main/java/cn/sh/stc/sict/cloud/auth/handler/SictAuthenticationFailureLockEventHandler.java +++ b/cloud-auth/src/main/java/cn/sh/stc/sict/cloud/auth/handler/SictAuthenticationFailureLockEventHandler.java @@ -2,8 +2,8 @@ package cn.sh.stc.sict.cloud.auth.handler; import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant; +import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties; import cn.sh.stc.sict.cloud.common.security.handler.AuthenticationFailureHandler; -import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService; import lombok.AllArgsConstructor; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; @@ -28,8 +28,7 @@ import java.util.concurrent.TimeUnit; public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler { private final RedisTemplate redisTemplate; - - private final RemoteUserService remoteUserService; + private final UserAccountProperties userAccountProperties; /** * 密码错误超过 5 此自动锁定 @@ -45,16 +44,14 @@ public class SictAuthenticationFailureLockEventHandler implements Authentication public void handle(AuthenticationException authenticationException, Authentication authentication, HttpServletRequest request, HttpServletResponse response) { // 只处理账号密码错误异常 - if (!(authenticationException instanceof BadCredentialsException)) { + if (!(authenticationException instanceof BadCredentialsException) && userAccountProperties.getLimitFlag()) { return; } String username = authentication.getName(); String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username); - Long deltaTimes = 5L; Long times = redisTemplate.opsForValue().increment(key); // 自动过期时间 - Long deltaTime = 30L; - redisTemplate.expire(key, deltaTime, TimeUnit.MINUTES); + redisTemplate.expire(key, userAccountProperties.getLimitTime(), TimeUnit.MINUTES); } } diff --git a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/NumberUtil.java b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/NumberUtil.java index 315ab0df088263ae925db2a73085825e874a9375..75bafab997fea5db835e81657142aef5e9b64e3c 100644 --- a/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/NumberUtil.java +++ b/cloud-common/cloud-common-core/src/main/java/cn/sh/stc/sict/cloud/common/core/util/NumberUtil.java @@ -1,6 +1,7 @@ package cn.sh.stc.sict.cloud.common.core.util; import cn.hutool.core.util.ObjectUtil; +import cn.hutool.core.util.StrUtil; import java.math.BigDecimal; import java.math.BigInteger; @@ -118,4 +119,7 @@ public class NumberUtil { } + public static Long getLongValue(String value) { + return StrUtil.isBlank(value) ? 0L : Long.parseLong(value); + } } diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/config/UserAccountProperties.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/config/UserAccountProperties.java new file mode 100644 index 0000000000000000000000000000000000000000..4e9615921b10f120bbcfce8e461041418a9c1338 --- /dev/null +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/config/UserAccountProperties.java @@ -0,0 +1,35 @@ +package cn.sh.stc.sict.cloud.common.security.config; + +import cn.hutool.core.util.ObjectUtil; +import cn.sh.stc.sict.cloud.common.core.util.NumberUtil; +import lombok.Data; +import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * 用户账号 配置属性 + */ +@Data +@Component +@RefreshScope +@ConditionalOnExpression("!'${user}'.isEmpty()") +@ConfigurationProperties(prefix = "user.account") +public class UserAccountProperties { + private Boolean limitFlag; + private Long limitCount; + private Long limitTime; + + public Boolean getLimitFlag() { + return !ObjectUtil.isNull(this.limitFlag) && this.limitFlag; + } + + public Long getLimitCount(){ + return NumberUtil.isNullOrZero(this.limitCount) ? 5L : this.limitCount; + } + + public Long getLimitTime() { + return NumberUtil.isNullOrZero(this.limitTime) ? 30L : this.limitTime; + } +} diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java index c32436f8089859e219fe8bd448c2400776260ab1..dc4a258721f79030cd7927311a563ee6261e1790 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUser.java @@ -58,7 +58,17 @@ public class SictUser extends User { * @throws IllegalArgumentException if a null value was passed either as * a parameter or as an element in the GrantedAuthority collection */ - public SictUser(Long id, String phone, String openId, String appId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection authorities) { + public SictUser(Long id, + String phone, + String openId, + String appId, + String username, + String password, + boolean enabled, + boolean accountNonExpired, + boolean credentialsNonExpired, + boolean accountNonLocked, + Collection authorities) { super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); this.id = id; this.phone = phone; diff --git a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java index 0b5e823a8ea05112328d19995d4f6964575f69dd..0e72e0b181a1d85a736e875856c072ea3164e29c 100644 --- a/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java +++ b/cloud-common/cloud-common-security/src/main/java/cn/sh/stc/sict/cloud/common/security/service/SictUserDetailsServiceImpl.java @@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil; import cn.sh.stc.sict.cloud.common.core.constant.Constant; import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant; import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants; +import cn.sh.stc.sict.cloud.common.core.util.NumberUtil; import cn.sh.stc.sict.cloud.common.core.util.R; +import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties; import cn.sh.stc.sict.cloud.common.security.util.AuthUtils; import cn.sh.stc.sict.cloud.upms.dto.UserInfo; import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService; @@ -16,6 +18,7 @@ import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import org.springframework.cache.Cache; import org.springframework.cache.CacheManager; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpHeaders; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.AuthorityUtils; @@ -26,6 +29,7 @@ import org.springframework.stereotype.Service; import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.ServletRequestAttributes; +import javax.security.auth.login.AccountLockedException; import javax.servlet.http.HttpServletRequest; import java.util.*; @@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { private static final String BASIC_ = "Basic "; private final RemoteUserService remoteUserService; private final CacheManager cacheManager; + private final RedisTemplate redisTemplate; + private final UserAccountProperties userAccountProperties; /** * 用户密码登录 + * . * * @param username 用户名 * @return @@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { @SneakyThrows public UserDetails loadUserByUsername(String username) { String key = username; + String lockedKey = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username); + Long times = NumberUtil.getLongValue(redisTemplate.opsForValue().get(lockedKey)); + if (userAccountProperties.getLimitFlag() && times >= userAccountProperties.getLimitCount()) { + throw new AccountLockedException("账号被锁定"); + } Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS); if (!StrUtil.containsAny(key, StringPool.COLON)) { key = key + StringPool.COLON + getAppId(); @@ -119,8 +131,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { } String userName = user.getUserName() + StringPool.COLON + info.getAppId(); - return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, SecurityConstants.BCRYPT + user.getPasswd(), enabled, - true, true, !Constant.BYTE_YES.equals(user.getStatus()), authorities); + String password = SecurityConstants.BCRYPT + user.getPasswd(); + // 登录失败5次锁定半小时 + boolean nonLockd = !Constant.BYTE_YES.equals(user.getStatus()); + return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, password, enabled, + true, true, nonLockd, authorities); } private static String getAppId() { diff --git a/cloud-common/cloud-common-security/src/main/resources/META-INF/spring.factories b/cloud-common/cloud-common-security/src/main/resources/META-INF/spring.factories index ed3c7408b8a102dc83390e2eaaf840780ed7b87a..12c5c482040560991d6e8023505388bd174192b5 100644 --- a/cloud-common/cloud-common-security/src/main/resources/META-INF/spring.factories +++ b/cloud-common/cloud-common-security/src/main/resources/META-INF/spring.factories @@ -1,6 +1,7 @@ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\ cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\ + cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties,\ cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl,\ cn.sh.stc.sict.cloud.common.security.component.SictWebResponseExceptionTranslator,\ cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\