Commit f8249b11 authored by 向怀芳's avatar 向怀芳 🎱

1. 新增账号锁定功能

parent 9dde27a6
...@@ -2,8 +2,8 @@ ...@@ -2,8 +2,8 @@
package cn.sh.stc.sict.cloud.auth.handler; 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.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.common.security.handler.AuthenticationFailureHandler;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
import lombok.AllArgsConstructor; import lombok.AllArgsConstructor;
import lombok.SneakyThrows; import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
...@@ -28,8 +28,7 @@ import java.util.concurrent.TimeUnit; ...@@ -28,8 +28,7 @@ import java.util.concurrent.TimeUnit;
public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler { public class SictAuthenticationFailureLockEventHandler implements AuthenticationFailureHandler {
private final RedisTemplate<String, String> redisTemplate; private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
private final RemoteUserService remoteUserService;
/** /**
* 密码错误超过 5 此自动锁定 * 密码错误超过 5 此自动锁定
...@@ -45,16 +44,14 @@ public class SictAuthenticationFailureLockEventHandler implements Authentication ...@@ -45,16 +44,14 @@ public class SictAuthenticationFailureLockEventHandler implements Authentication
public void handle(AuthenticationException authenticationException, Authentication authentication, public void handle(AuthenticationException authenticationException, Authentication authentication,
HttpServletRequest request, HttpServletResponse response) { HttpServletRequest request, HttpServletResponse response) {
// 只处理账号密码错误异常 // 只处理账号密码错误异常
if (!(authenticationException instanceof BadCredentialsException)) { if (!(authenticationException instanceof BadCredentialsException) && userAccountProperties.getLimitFlag()) {
return; return;
} }
String username = authentication.getName(); String username = authentication.getName();
String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username); String key = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long deltaTimes = 5L;
Long times = redisTemplate.opsForValue().increment(key); Long times = redisTemplate.opsForValue().increment(key);
// 自动过期时间 // 自动过期时间
Long deltaTime = 30L; redisTemplate.expire(key, userAccountProperties.getLimitTime(), TimeUnit.MINUTES);
redisTemplate.expire(key, deltaTime, TimeUnit.MINUTES);
} }
} }
package cn.sh.stc.sict.cloud.common.core.util; package cn.sh.stc.sict.cloud.common.core.util;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.math.BigInteger; import java.math.BigInteger;
...@@ -118,4 +119,7 @@ public class NumberUtil { ...@@ -118,4 +119,7 @@ public class NumberUtil {
} }
public static Long getLongValue(String value) {
return StrUtil.isBlank(value) ? 0L : Long.parseLong(value);
}
} }
package cn.sh.stc.sict.cloud.common.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;
}
}
...@@ -58,7 +58,17 @@ public class SictUser extends User { ...@@ -58,7 +58,17 @@ public class SictUser extends User {
* @throws IllegalArgumentException if a <code>null</code> value was passed either as * @throws IllegalArgumentException if a <code>null</code> value was passed either as
* a parameter or as an element in the <code>GrantedAuthority</code> collection * a parameter or as an element in the <code>GrantedAuthority</code> collection
*/ */
public SictUser(Long id, String phone, String openId, String appId, String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) { public SictUser(Long id,
String phone,
String openId,
String appId,
String username,
String password,
boolean enabled,
boolean accountNonExpired,
boolean credentialsNonExpired,
boolean accountNonLocked,
Collection<? extends GrantedAuthority> authorities) {
super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities); super(username, password, enabled, accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
this.id = id; this.id = id;
this.phone = phone; this.phone = phone;
......
...@@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil; ...@@ -5,7 +5,9 @@ import cn.hutool.core.util.StrUtil;
import cn.sh.stc.sict.cloud.common.core.constant.Constant; import cn.sh.stc.sict.cloud.common.core.constant.Constant;
import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant; import cn.sh.stc.sict.cloud.common.core.constant.RedisCacheConstant;
import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants; import cn.sh.stc.sict.cloud.common.core.constant.SecurityConstants;
import cn.sh.stc.sict.cloud.common.core.util.NumberUtil;
import cn.sh.stc.sict.cloud.common.core.util.R; import cn.sh.stc.sict.cloud.common.core.util.R;
import cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties;
import cn.sh.stc.sict.cloud.common.security.util.AuthUtils; import cn.sh.stc.sict.cloud.common.security.util.AuthUtils;
import cn.sh.stc.sict.cloud.upms.dto.UserInfo; import cn.sh.stc.sict.cloud.upms.dto.UserInfo;
import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService; import cn.sh.stc.sict.cloud.upms.feign.RemoteUserService;
...@@ -16,6 +18,7 @@ import lombok.SneakyThrows; ...@@ -16,6 +18,7 @@ import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.Cache; import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager; import org.springframework.cache.CacheManager;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders; import org.springframework.http.HttpHeaders;
import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils; import org.springframework.security.core.authority.AuthorityUtils;
...@@ -26,6 +29,7 @@ import org.springframework.stereotype.Service; ...@@ -26,6 +29,7 @@ import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder; import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.context.request.ServletRequestAttributes;
import javax.security.auth.login.AccountLockedException;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequest;
import java.util.*; import java.util.*;
...@@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -42,9 +46,12 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
private static final String BASIC_ = "Basic "; private static final String BASIC_ = "Basic ";
private final RemoteUserService remoteUserService; private final RemoteUserService remoteUserService;
private final CacheManager cacheManager; private final CacheManager cacheManager;
private final RedisTemplate<String, String> redisTemplate;
private final UserAccountProperties userAccountProperties;
/** /**
* 用户密码登录 * 用户密码登录
* .
* *
* @param username 用户名 * @param username 用户名
* @return * @return
...@@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -54,6 +61,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
@SneakyThrows @SneakyThrows
public UserDetails loadUserByUsername(String username) { public UserDetails loadUserByUsername(String username) {
String key = username; String key = username;
String lockedKey = String.format("%s:%s", RedisCacheConstant.LOGIN_ERROR_TIMES, username);
Long times = NumberUtil.getLongValue(redisTemplate.opsForValue().get(lockedKey));
if (userAccountProperties.getLimitFlag() && times >= userAccountProperties.getLimitCount()) {
throw new AccountLockedException("账号被锁定");
}
Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS); Cache cache = cacheManager.getCache(RedisCacheConstant.USER_DETAILS);
if (!StrUtil.containsAny(key, StringPool.COLON)) { if (!StrUtil.containsAny(key, StringPool.COLON)) {
key = key + StringPool.COLON + getAppId(); key = key + StringPool.COLON + getAppId();
...@@ -119,8 +131,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService { ...@@ -119,8 +131,11 @@ public class SictUserDetailsServiceImpl implements SictUserDetailsService {
} }
String userName = user.getUserName() + StringPool.COLON + info.getAppId(); String userName = user.getUserName() + StringPool.COLON + info.getAppId();
return new SictUser(user.getId(), user.getPhone(), info.getOpenId(), info.getAppId(), userName, SecurityConstants.BCRYPT + user.getPasswd(), enabled, String password = SecurityConstants.BCRYPT + user.getPasswd();
true, true, !Constant.BYTE_YES.equals(user.getStatus()), authorities); // 登录失败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() { private static String getAppId() {
......
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\ org.springframework.cloud.openfeign.SictHystrixFeignTargeterConfiguration,\
cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\ cn.sh.stc.sict.cloud.common.security.feign.SictFeignConfiguration,\
cn.sh.stc.sict.cloud.common.security.config.UserAccountProperties,\
cn.sh.stc.sict.cloud.common.security.service.SictUserDetailsServiceImpl,\ 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.SictWebResponseExceptionTranslator,\
cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\ cn.sh.stc.sict.cloud.common.security.component.ResourceAuthExceptionEntryPoint,\
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment