mirror of https://gitee.com/stylefeng/roses
【7.1.6】去除druid广告&增加密码错误次数限定
parent
79557723fe
commit
bc352d374a
|
@ -114,4 +114,11 @@ public interface AuthServiceApi {
|
|||
*/
|
||||
void checkAuth(String token, String requestUrl);
|
||||
|
||||
/**
|
||||
* 取消冻结帐号
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 16:37
|
||||
*/
|
||||
void cancelFreeze(LoginRequest loginRequest);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package cn.stylefeng.roses.kernel.auth.api.constants;
|
||||
|
||||
/**
|
||||
* 登录前缀相关的常量
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 17:37
|
||||
*/
|
||||
public interface LoginCacheConstants {
|
||||
|
||||
/**
|
||||
* 登录最大次数
|
||||
*/
|
||||
Integer MAX_LOGIN_COUNT = 5;
|
||||
|
||||
/**
|
||||
* 登录冻结缓存前缀
|
||||
*/
|
||||
String LOGIN_CACHE_PREFIX = "login:";
|
||||
|
||||
/**
|
||||
* 冻结时间
|
||||
*/
|
||||
Long LOGIN_CACHE_TIMEOUT_SECONDS = 1800L;
|
||||
}
|
|
@ -121,7 +121,12 @@ public enum AuthExceptionEnum implements AbstractExceptionEnum {
|
|||
/**
|
||||
* 无法访问未经授权的接口
|
||||
*/
|
||||
CANT_REQUEST_UN_OPEN_API(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "17", "无法访问未经授权的接口,未授权url为:{}");
|
||||
CANT_REQUEST_UN_OPEN_API(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "17", "无法访问未经授权的接口,未授权url为:{}"),
|
||||
|
||||
/**
|
||||
* 超过最大登录次数
|
||||
*/
|
||||
EXCEED_MAX_LOGIN_COUNT(RuleConstants.BUSINESS_ERROR_TYPE_CODE + AuthConstants.AUTH_EXCEPTION_STEP_CODE + "18", "超过最大登录次数,帐号被锁定");
|
||||
|
||||
/**
|
||||
* 错误编码
|
||||
|
|
|
@ -126,6 +126,11 @@
|
|||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>system-business-user</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
*/
|
||||
package cn.stylefeng.roses.kernel.auth.auth;
|
||||
|
||||
import cn.hutool.core.bean.BeanUtil;
|
||||
import cn.hutool.core.codec.Base64;
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
|
@ -36,6 +37,7 @@ import cn.hutool.http.HttpResponse;
|
|||
import cn.stylefeng.roses.kernel.auth.api.AuthServiceApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants;
|
||||
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
|
||||
import cn.stylefeng.roses.kernel.auth.api.context.LoginContext;
|
||||
import cn.stylefeng.roses.kernel.auth.api.exception.AuthException;
|
||||
import cn.stylefeng.roses.kernel.auth.api.exception.enums.AuthExceptionEnum;
|
||||
|
@ -47,6 +49,9 @@ import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginRequest;
|
|||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginResponse;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.auth.LoginWithTokenRequest;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import cn.stylefeng.roses.kernel.auth.session.cache.loginuser.RedisLoginUserCache;
|
||||
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
|
||||
import cn.stylefeng.roses.kernel.cache.memory.operator.DefaultMemoryCacheOperator;
|
||||
import cn.stylefeng.roses.kernel.demo.expander.DemoConfigExpander;
|
||||
import cn.stylefeng.roses.kernel.jwt.JwtTokenOperator;
|
||||
import cn.stylefeng.roses.kernel.jwt.api.context.JwtContext;
|
||||
|
@ -66,10 +71,13 @@ import cn.stylefeng.roses.kernel.system.api.ResourceServiceApi;
|
|||
import cn.stylefeng.roses.kernel.system.api.UserServiceApi;
|
||||
import cn.stylefeng.roses.kernel.system.api.enums.UserStatusEnum;
|
||||
import cn.stylefeng.roses.kernel.system.api.pojo.user.UserLoginInfoDTO;
|
||||
import cn.stylefeng.roses.kernel.system.modular.user.entity.SysUser;
|
||||
import cn.stylefeng.roses.kernel.system.modular.user.service.SysUserService;
|
||||
import cn.stylefeng.roses.kernel.validator.api.exception.enums.ValidatorExceptionEnum;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import io.jsonwebtoken.Claims;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
@ -119,6 +127,15 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
@Resource
|
||||
private ResourceServiceApi resourceServiceApi;
|
||||
|
||||
@Resource
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@Resource
|
||||
private CacheOperatorApi<String> loginCacheOperatorApi;
|
||||
|
||||
@Value("${login.enable}")
|
||||
private Boolean enable;
|
||||
|
||||
@Override
|
||||
public LoginResponse login(LoginRequest loginRequest) {
|
||||
return loginAction(loginRequest, true, null);
|
||||
|
@ -254,6 +271,25 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
* @date 2020/10/21 16:59
|
||||
*/
|
||||
private LoginResponse loginAction(LoginRequest loginRequest, Boolean validatePassword, String caToken) {
|
||||
SysUser userByAccount = sysUserService.getUserByAccount(loginRequest.getAccount());
|
||||
// 判断登录错误检测是否开启
|
||||
if (enable) {
|
||||
// 判断错误次数,超过最大放入缓存中
|
||||
if (StrUtil.isBlank(loginCacheOperatorApi.get(userByAccount.getUserId().toString()))) {
|
||||
if (userByAccount.getLoginCount() > LoginCacheConstants.MAX_LOGIN_COUNT) {
|
||||
loginCacheOperatorApi.put(userByAccount.getUserId().toString(), "true", 1800L);
|
||||
throw new AuthException(AuthExceptionEnum.EXCEED_MAX_LOGIN_COUNT);
|
||||
}
|
||||
} else {
|
||||
throw new AuthException(AuthExceptionEnum.EXCEED_MAX_LOGIN_COUNT);
|
||||
}
|
||||
}
|
||||
|
||||
// 5. 获取用户密码的加密值和用户的状态
|
||||
UserLoginInfoDTO userValidateInfo = userServiceApi.getUserLoginInfo(loginRequest.getAccount());
|
||||
|
||||
// 8. 获取LoginUser,用于用户的缓存
|
||||
LoginUser loginUser = userValidateInfo.getLoginUser();
|
||||
|
||||
// 1.参数为空校验
|
||||
if (validatePassword) {
|
||||
|
@ -275,6 +311,8 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY);
|
||||
}
|
||||
if (!captchaApi.validateCaptcha(verKey, verCode)) {
|
||||
// 登录失败日志
|
||||
loginLogServiceApi.loginFail(loginUser.getUserId(), "验证码错误");
|
||||
throw new AuthException(ValidatorExceptionEnum.CAPTCHA_ERROR);
|
||||
}
|
||||
}
|
||||
|
@ -288,6 +326,8 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
throw new AuthException(ValidatorExceptionEnum.CAPTCHA_EMPTY);
|
||||
}
|
||||
if (!dragCaptchaApi.validateCaptcha(verKey, Convert.toInt(verXLocationValue))) {
|
||||
// 登录失败日志
|
||||
loginLogServiceApi.loginFail(loginUser.getUserId(), "拖拽验证码错误");
|
||||
throw new AuthException(ValidatorExceptionEnum.DRAG_CAPTCHA_ERROR);
|
||||
}
|
||||
}
|
||||
|
@ -308,13 +348,15 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
return new LoginResponse(remoteLoginCode);
|
||||
}
|
||||
|
||||
// 5. 获取用户密码的加密值和用户的状态
|
||||
UserLoginInfoDTO userValidateInfo = userServiceApi.getUserLoginInfo(loginRequest.getAccount());
|
||||
|
||||
// 6. 校验用户密码是否正确
|
||||
if (validatePassword) {
|
||||
Boolean checkResult = passwordStoredEncryptApi.checkPassword(loginRequest.getPassword(), userValidateInfo.getUserPasswordHexed());
|
||||
if (!checkResult) {
|
||||
//更新登录次数
|
||||
userByAccount.setLoginCount(userByAccount.getLoginCount() + 1);
|
||||
sysUserService.updateById(userByAccount);
|
||||
// 登录失败日志
|
||||
loginLogServiceApi.loginFail(loginUser.getUserId(), "帐号或密码错误");
|
||||
throw new AuthException(AuthExceptionEnum.USERNAME_PASSWORD_ERROR);
|
||||
}
|
||||
}
|
||||
|
@ -324,9 +366,6 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
throw new AuthException(AuthExceptionEnum.USER_STATUS_ERROR, UserStatusEnum.getCodeMessage(userValidateInfo.getUserStatus()));
|
||||
}
|
||||
|
||||
// 8. 获取LoginUser,用于用户的缓存
|
||||
LoginUser loginUser = userValidateInfo.getLoginUser();
|
||||
|
||||
// 9. 生成用户的token
|
||||
DefaultJwtPayload defaultJwtPayload = new DefaultJwtPayload(loginUser.getUserId(), loginUser.getAccount(), loginRequest.getRememberMe(), caToken);
|
||||
String jwtToken = JwtContext.me().generateTokenDefaultPayload(defaultJwtPayload);
|
||||
|
@ -355,6 +394,10 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
String ip = HttpServletUtil.getRequestClientIp(HttpServletUtil.getRequest());
|
||||
userServiceApi.updateUserLoginInfo(loginUser.getUserId(), new Date(), ip);
|
||||
|
||||
//重置登录次数
|
||||
userByAccount.setLoginCount(1);
|
||||
sysUserService.updateById(userByAccount);
|
||||
|
||||
// 13.登录成功日志
|
||||
loginLogServiceApi.loginSuccess(loginUser.getUserId());
|
||||
}
|
||||
|
@ -403,4 +446,13 @@ public class AuthServiceImpl implements AuthServiceApi {
|
|||
return loginCode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cancelFreeze(LoginRequest loginRequest) {
|
||||
SysUser sysUser = sysUserService.getUserByAccount(loginRequest.getAccount());
|
||||
sysUser.setLoginCount(1);
|
||||
// 修改数据库中的登录次数
|
||||
sysUserService.updateById(sysUser);
|
||||
// 删除缓存中的数据
|
||||
loginCacheOperatorApi.remove(sysUser.getUserId().toString());
|
||||
}
|
||||
}
|
||||
|
|
23
kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/cache/LoginMemoryCache.java
vendored
Normal file
23
kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/cache/LoginMemoryCache.java
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
package cn.stylefeng.roses.kernel.auth.cache;
|
||||
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
|
||||
import cn.stylefeng.roses.kernel.cache.memory.AbstractMemoryCacheOperator;
|
||||
|
||||
/**
|
||||
* 用户帐号冻结的缓存
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 17:33
|
||||
*/
|
||||
public class LoginMemoryCache extends AbstractMemoryCacheOperator<String> {
|
||||
|
||||
public LoginMemoryCache(TimedCache<String, String> timedCache) {
|
||||
super(timedCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LoginCacheConstants.LOGIN_CACHE_PREFIX;
|
||||
}
|
||||
}
|
23
kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/cache/LoginRedisCache.java
vendored
Normal file
23
kernel-d-auth/auth-sdk/src/main/java/cn/stylefeng/roses/kernel/auth/cache/LoginRedisCache.java
vendored
Normal file
|
@ -0,0 +1,23 @@
|
|||
package cn.stylefeng.roses.kernel.auth.cache;
|
||||
|
||||
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
|
||||
import cn.stylefeng.roses.kernel.cache.redis.AbstractRedisCacheOperator;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
/**
|
||||
* 用户帐号冻结的缓存
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/23 23:34
|
||||
*/
|
||||
public class LoginRedisCache extends AbstractRedisCacheOperator<String> {
|
||||
|
||||
public LoginRedisCache(RedisTemplate<String, String> redisTemplate) {
|
||||
super(redisTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LoginCacheConstants.LOGIN_CACHE_PREFIX;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
package cn.stylefeng.roses.kernel.auth.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 控制帐号错误检测开关
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/23 23:42
|
||||
*/
|
||||
@Data
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "login")
|
||||
public class AccountErrorDetectionConfig {
|
||||
|
||||
/**
|
||||
* 开关:true-开启错误检测,false-关闭错误检测
|
||||
*/
|
||||
private Boolean enable;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package cn.stylefeng.roses.kernel.auth.starter;
|
||||
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.stylefeng.roses.kernel.auth.api.constants.LoginCacheConstants;
|
||||
import cn.stylefeng.roses.kernel.auth.cache.LoginMemoryCache;
|
||||
import cn.stylefeng.roses.kernel.cache.api.CacheOperatorApi;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 登录缓存的自动配置
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 17:40
|
||||
*/
|
||||
@Configuration
|
||||
public class GunsLoginCacheAutoConfiguration {
|
||||
|
||||
/**
|
||||
* 登录帐号冻结的缓存
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 17:45
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnMissingBean(name = "loginCacheOperatorApi")
|
||||
public CacheOperatorApi<String> loginCacheOperatorApi() {
|
||||
TimedCache<String, String> loginTimeCache = CacheUtil.newTimedCache(LoginCacheConstants.LOGIN_CACHE_TIMEOUT_SECONDS * 1000);
|
||||
return new LoginMemoryCache(loginTimeCache);
|
||||
}
|
||||
}
|
|
@ -1,3 +1,4 @@
|
|||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
cn.stylefeng.roses.kernel.auth.starter.GunsAuthAutoConfiguration,\
|
||||
cn.stylefeng.roses.kernel.auth.starter.GunsSsoAutoConfiguration
|
||||
cn.stylefeng.roses.kernel.auth.starter.GunsSsoAutoConfiguration,\
|
||||
cn.stylefeng.roses.kernel.auth.starter.GunsLoginCacheAutoConfiguration
|
|
@ -38,6 +38,11 @@
|
|||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>druid-spring-boot-starter</artifactId>
|
||||
<version>1.2.8</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,68 @@
|
|||
package cn.stylefeng.roses.kernel.db.starter;
|
||||
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure;
|
||||
import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
|
||||
import com.alibaba.druid.util.Utils;
|
||||
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import javax.servlet.*;
|
||||
import java.io.IOException;
|
||||
|
||||
@Configuration
|
||||
@ConditionalOnWebApplication
|
||||
@AutoConfigureAfter(DruidDataSourceAutoConfigure.class)
|
||||
@ConditionalOnProperty(name = "spring.datasource.druid.stat-view-servlet.enabled", havingValue = "true", matchIfMissing = true)
|
||||
public class RemoveDruidAdConfig {
|
||||
|
||||
|
||||
/**
|
||||
* 方法名: removeDruidAdFilterRegistrationBean
|
||||
* 方法描述: 除去页面底部的广告
|
||||
* @param properties
|
||||
* @return org.springframework.boot.web.servlet.FilterRegistrationBean
|
||||
* @throws
|
||||
*/
|
||||
@Bean
|
||||
public FilterRegistrationBean removeDruidAdFilterRegistrationBean(DruidStatProperties properties) {
|
||||
// 获取web监控页面的参数
|
||||
DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
|
||||
// 提取common.js的配置路径
|
||||
String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
|
||||
String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
|
||||
|
||||
final String filePath = "support/http/resources/js/common.js";
|
||||
|
||||
//创建filter进行过滤
|
||||
Filter filter = new Filter() {
|
||||
@Override
|
||||
public void init(FilterConfig filterConfig) throws ServletException {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
|
||||
chain.doFilter(request, response);
|
||||
// 重置缓冲区,响应头不会被重置
|
||||
response.resetBuffer();
|
||||
// 获取common.js
|
||||
String text = Utils.readFromResource(filePath);
|
||||
// 正则替换banner, 除去底部的广告信息
|
||||
text = text.replaceAll("<a.*?banner\"></a><br/>", "");
|
||||
text = text.replaceAll("powered.*?shrek.wang</a>", "");
|
||||
response.getWriter().write(text);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() {
|
||||
}
|
||||
};
|
||||
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
|
||||
registrationBean.setFilter(filter);
|
||||
registrationBean.addUrlPatterns(commonJsPattern);
|
||||
return registrationBean;
|
||||
}
|
||||
}
|
|
@ -114,11 +114,11 @@
|
|||
</dependency>
|
||||
|
||||
<!--登录sdk-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>auth-sdk</artifactId>
|
||||
<version>${roses.version}</version>
|
||||
</dependency>
|
||||
<!--<dependency>-->
|
||||
<!-- <groupId>cn.stylefeng.roses</groupId>-->
|
||||
<!-- <artifactId>auth-sdk</artifactId>-->
|
||||
<!-- <version>${roses.version}</version>-->
|
||||
<!--</dependency>-->
|
||||
|
||||
<!--web模块-->
|
||||
<dependency>
|
||||
|
@ -126,6 +126,20 @@
|
|||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--jwt-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>jwt-api</artifactId>
|
||||
<version>7.1.6</version>
|
||||
</dependency>
|
||||
|
||||
<!--message-->
|
||||
<dependency>
|
||||
<groupId>cn.stylefeng.roses</groupId>
|
||||
<artifactId>message-api</artifactId>
|
||||
<version>7.1.6</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -143,4 +143,15 @@ public class LoginController {
|
|||
return new SuccessResponseData<>(haveSessionFlag);
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消帐号冻结
|
||||
*
|
||||
* @author xixiaowei
|
||||
* @date 2022/1/22 16:40
|
||||
*/
|
||||
@PostResource(name = "取消帐号冻结", path = "/cancelFreeze")
|
||||
public ResponseData<?> cancelFreeze(@RequestBody LoginRequest loginRequest) {
|
||||
authServiceApi.cancelFreeze(loginRequest);
|
||||
return new SuccessResponseData<>();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -154,4 +154,9 @@ public class SysUser extends BaseEntity {
|
|||
@TableField(value = "del_flag", fill = FieldFill.INSERT)
|
||||
private String delFlag;
|
||||
|
||||
/**
|
||||
* 登录次数
|
||||
*/
|
||||
@TableField("login_count")
|
||||
private Integer loginCount;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue