Quellcode durchsuchen

1、新增登出接口
2、登录判断ip是否存在,不存在就异常弹出

liyanbo vor 7 Monaten
Ursprung
Commit
07aaa04fb5

+ 1 - 0
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/enums/ErrorCodeConstants.java

@@ -16,6 +16,7 @@ public interface ErrorCodeConstants {
     ErrorCode AUTH_THIRD_LOGIN_NOT_BIND = new ErrorCode(1_002_000_005, "未绑定账号,需要进行绑定");
     ErrorCode AUTH_MOBILE_NOT_EXISTS = new ErrorCode(1_002_000_007, "手机号不存在");
     ErrorCode AUTH_REGISTER_CAPTCHA_CODE_ERROR = new ErrorCode(1_002_000_008, "验证码不正确,原因:{}");
+    ErrorCode AUTH_LOGIN_IP_NOT_AUTHORIZED = new ErrorCode(1_002_000_009, "登录IP未被授权");
 
     // ========== 菜单模块 1-002-001-000 ==========
     ErrorCode MENU_NAME_DUPLICATE = new ErrorCode(1_002_001_000, "已经存在该名字的菜单");

+ 25 - 0
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/service/auth/AdminAuthServiceImpl.java

@@ -6,6 +6,8 @@ import cn.iocoder.byzs.framework.common.enums.UserTypeEnum;
 import cn.iocoder.byzs.framework.common.util.monitor.TracerUtils;
 import cn.iocoder.byzs.framework.common.util.servlet.ServletUtils;
 import cn.iocoder.byzs.framework.common.util.validation.ValidationUtils;
+import cn.iocoder.byzs.framework.tenant.core.context.TenantContextHolder;
+import cn.iocoder.byzs.framework.web.core.util.WebFrameworkUtils;
 import cn.iocoder.byzs.module.system.api.logger.dto.LoginLogCreateReqDTO;
 import cn.iocoder.byzs.module.system.api.sms.SmsCodeApi;
 import cn.iocoder.byzs.module.system.api.sms.dto.code.SmsCodeUseReqDTO;
@@ -37,9 +39,12 @@ import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 import java.util.Objects;
+import java.util.Set;
 
 import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.byzs.framework.common.util.servlet.ServletUtils.getClientIP;
 import static cn.iocoder.byzs.module.system.enums.ErrorCodeConstants.*;
 
@@ -208,8 +213,28 @@ public class AdminAuthServiceImpl implements AdminAuthService {
     }
 
     private AuthLoginRespVO createTokenAfterLoginSuccess(Long userId, String username, LoginLogTypeEnum logType) {
+
+        // 删除用户之前的所有令牌,实现单点登录(默认租户用户可以多设备登录)
+        if (!Objects.equals(TenantContextHolder.getTenantId(), WebFrameworkUtils.DEFAULT_TENANT_ID)){
+            // 删除用户之前的所有令牌,实现单点登录(默认租户用户可以多设备登录)
+            oauth2TokenService.removeUserTokens(userId, getUserType().getValue());
+
+            //查看登录ip是否已被授权
+            Set<String> userLoginIpSet = loginLogService.selectIpListByUserId(userId);
+            if(!userLoginIpSet.contains(ServletUtils.getClientIP())){
+
+                //需要手机号校验
+                //发送手机验证码
+                AuthSmsLoginReqVO authSmsLoginReqVO = new AuthSmsLoginReqVO().setMobile(username);
+//                smsCodeApi.sendSmsCode(AuthConvert.INSTANCE.convert(authSmsLoginReqVO));
+
+                throw exception(AUTH_LOGIN_IP_NOT_AUTHORIZED);
+            }
+        }
+
         // 插入登陆日志
         createLoginLog(userId, username, logType, LoginResultEnum.SUCCESS);
+
         // 创建访问令牌
         OAuth2AccessTokenDO accessTokenDO = oauth2TokenService.createAccessToken(userId, getUserType().getValue(),
                 OAuth2ClientConstants.CLIENT_ID_DEFAULT, null);

+ 10 - 1
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/service/logger/LoginLogService.java

@@ -4,8 +4,10 @@ import cn.iocoder.byzs.framework.common.pojo.PageResult;
 import cn.iocoder.byzs.module.system.api.logger.dto.LoginLogCreateReqDTO;
 import cn.iocoder.byzs.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO;
 import cn.iocoder.byzs.module.system.dal.dataobject.logger.LoginLogDO;
-
 import jakarta.validation.Valid;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Set;
 
 /**
  * 登录日志 Service 接口
@@ -27,4 +29,11 @@ public interface LoginLogService {
      */
     void createLoginLog(@Valid LoginLogCreateReqDTO reqDTO);
 
+    /**
+     * 查询登录用户ip集
+     *
+     * @param userId 日志信息
+     */
+    Set<String> selectIpListByUserId(@Param("userId") Long userId);
+
 }

+ 21 - 0
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/service/logger/LoginLogServiceImpl.java

@@ -6,11 +6,18 @@ import cn.iocoder.byzs.module.system.api.logger.dto.LoginLogCreateReqDTO;
 import cn.iocoder.byzs.module.system.controller.admin.logger.vo.loginlog.LoginLogPageReqVO;
 import cn.iocoder.byzs.module.system.dal.dataobject.logger.LoginLogDO;
 import cn.iocoder.byzs.module.system.dal.mysql.logger.LoginLogMapper;
+import cn.iocoder.byzs.module.system.enums.logger.LoginResultEnum;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
 import jakarta.annotation.Resource;
 
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
 /**
  * 登录日志 Service 实现
  */
@@ -32,4 +39,18 @@ public class LoginLogServiceImpl implements LoginLogService {
         loginLogMapper.insert(loginLog);
     }
 
+    @Override
+    public Set<String> selectIpListByUserId(Long userId) {
+        List<LoginLogDO> loginLogDOS = loginLogMapper.selectList(new LambdaQueryWrapper<LoginLogDO>()
+                .select(LoginLogDO::getUserIp)
+                .eq(LoginLogDO::getUserId, userId)
+                .eq(LoginLogDO::getResult, LoginResultEnum.SUCCESS.getResult()));
+        if (loginLogDOS == null || loginLogDOS.isEmpty()) {
+            return Collections.emptySet();
+        }
+        return loginLogDOS.stream()
+                .map(LoginLogDO::getUserIp)
+                .collect(Collectors.toSet());
+    }
+
 }

+ 8 - 0
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/service/oauth2/OAuth2TokenService.java

@@ -29,6 +29,14 @@ public interface OAuth2TokenService {
      */
     OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes);
 
+    /**
+     * 删除指定用户的所有令牌
+     *
+     * @param userId 用户ID
+     * @param userType 用户类型
+     */
+    void removeUserTokens(Long userId, Integer userType);
+
     /**
      * 刷新访问令牌
      *

+ 2 - 6
byzs-module-system/src/main/java/cn/iocoder/byzs/module/system/service/oauth2/OAuth2TokenServiceImpl.java

@@ -61,11 +61,6 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
     public OAuth2AccessTokenDO createAccessToken(Long userId, Integer userType, String clientId, List<String> scopes) {
         OAuth2ClientDO clientDO = oauth2ClientService.validOAuthClientFromCache(clientId);
 
-        // 删除用户之前的所有令牌,实现单点登录(默认租户用户可以多设备登录)
-        if (!Objects.equals(TenantContextHolder.getTenantId(), WebFrameworkUtils.DEFAULT_TENANT_ID)){
-            removeUserTokens(userId, userType);
-        }
-
         // 创建刷新令牌
         OAuth2RefreshTokenDO refreshTokenDO = createOAuth2RefreshToken(userId, userType, clientDO, scopes);
         // 创建访问令牌
@@ -78,7 +73,8 @@ public class OAuth2TokenServiceImpl implements OAuth2TokenService {
      * @param userId 用户ID
      * @param userType 用户类型
      */
-    private void removeUserTokens(Long userId, Integer userType) {
+    @Override
+    public void removeUserTokens(Long userId, Integer userType) {
         // 查询用户的所有访问令牌
         List<OAuth2AccessTokenDO> accessTokenDOs = oauth2AccessTokenMapper.selectListByUserIdAndUserType(userId, userType);
         if (CollUtil.isNotEmpty(accessTokenDOs)) {

+ 20 - 0
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/login/WebLoginController.java

@@ -1,10 +1,14 @@
 package cn.iocoder.byzs.module.web.controller.admin.login;
 
+import cn.hutool.core.util.StrUtil;
 import cn.iocoder.byzs.framework.common.pojo.CommonResult;
+import cn.iocoder.byzs.framework.security.config.SecurityProperties;
+import cn.iocoder.byzs.framework.security.core.util.SecurityFrameworkUtils;
 import cn.iocoder.byzs.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.byzs.module.system.controller.admin.auth.vo.AuthLoginReqVO;
 import cn.iocoder.byzs.module.system.controller.admin.auth.vo.AuthLoginRespVO;
 import cn.iocoder.byzs.module.system.dal.dataobject.tenant.TenantDO;
+import cn.iocoder.byzs.module.system.enums.logger.LoginLogTypeEnum;
 import cn.iocoder.byzs.module.system.service.auth.AdminAuthService;
 import cn.iocoder.byzs.module.system.service.tenant.TenantService;
 import io.swagger.v3.oas.annotations.Operation;
@@ -12,6 +16,7 @@ import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
 import jakarta.annotation.security.PermitAll;
+import jakarta.servlet.http.HttpServletRequest;
 import jakarta.validation.Valid;
 import org.springframework.web.bind.annotation.*;
 
@@ -26,6 +31,8 @@ public class WebLoginController {
     private TenantService tenantService;
     @Resource
     private AdminAuthService authService;
+    @Resource
+    private SecurityProperties securityProperties;
 
 
     @GetMapping("/getTenantIdByName")
@@ -45,4 +52,17 @@ public class WebLoginController {
     public CommonResult<AuthLoginRespVO> login(@RequestBody @Valid AuthLoginReqVO reqVO) {
         return success(authService.login(reqVO));
     }
+
+
+    @PostMapping("/logout")
+    @PermitAll
+    @Operation(summary = "登出系统")
+    public CommonResult<Boolean> logout(HttpServletRequest request) {
+        String token = SecurityFrameworkUtils.obtainAuthorization(request,
+                securityProperties.getTokenHeader(), securityProperties.getTokenParameter());
+        if (StrUtil.isNotBlank(token)) {
+            authService.logout(token, LoginLogTypeEnum.LOGOUT_SELF.getType());
+        }
+        return success(true);
+    }
 }