Skip to content

Dev#5910

Merged
KouShenhai merged 2 commits intomasterfrom
dev
Mar 20, 2026
Merged

Dev#5910
KouShenhai merged 2 commits intomasterfrom
dev

Conversation

@KouShenhai
Copy link
Owner

@KouShenhai KouShenhai commented Mar 20, 2026

Summary by Sourcery

通过在内部处理异常并进行日志记录,同时简化认证流程,改进认证领域和基础设施层的错误处理。

增强内容:

  • 为认证聚合和登录日志转换器添加日志记录,在处理底层异常时通过抛出带有上下文日志信息的 IllegalArgumentException 来封装异常。
  • 优化登录事件转换,对 IP/地址解析错误进行封装,通过结构化日志记录来处理,而不是向外传播受检异常。
  • 从认证创建流程和 OAuth2 认证提供者方法中移除受检异常的向外传播,以简化方法签名和控制流。
  • 简化 UserDetailsServiceImpl,将异常处理下沉到更底层,并直接从认证结果中返回用户详情。
Original summary in English

Summary by Sourcery

Improve auth domain and infrastructure error handling by internalizing exceptions and logging while simplifying authentication flows.

Enhancements:

  • Add logging to auth aggregate and login log converter and handle low-level exceptions by throwing IllegalArgumentException with contextual logs.
  • Refine login event conversion to wrap IP/address resolution errors with structured logging instead of propagating checked exceptions.
  • Remove checked exception propagation from auth creation and OAuth2 authentication provider methods to simplify method signatures and control flow.
  • Simplify UserDetailsServiceImpl by delegating exception handling to lower layers and returning user details directly from the authentication result.

Summary by CodeRabbit

  • Refactor

    • Enhanced authentication error handling and logging mechanisms in the service layer.
    • Improved exception handling consistency across authentication providers.
  • Chores

    • Removed unused imports.

@netlify
Copy link

netlify bot commented Mar 20, 2026

Deploy Preview for kcloud-platform-iot ready!

Name Link
🔨 Latest commit cc742e0
🔍 Latest deploy log https://app.netlify.com/projects/kcloud-platform-iot/deploys/69bcd5bdfa075f00081b01b7
😎 Deploy Preview https://deploy-preview-5910--kcloud-platform-iot.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@sourcery-ai
Copy link

sourcery-ai bot commented Mar 20, 2026

Reviewer's Guide

本次 PR 优化了认证域和基础设施层中的异常处理与日志记录,尤其是围绕用户创建和登录日志记录的部分,并通过从认证流程中移除受检异常来简化方法签名。

带精细化异常处理的 OAuth2 认证流程时序图

sequenceDiagram
    actor Client
    participant OAuth2UsernamePasswordAuthenticationProvider
    participant AbstractOAuth2AuthenticationProvider
    participant OAuth2AuthenticationProcessor
    participant AuthA
    participant LoginLogConvertor
    participant AddressUtils
    participant DomainEventPublisher

    Client->>OAuth2UsernamePasswordAuthenticationProvider: authenticate
    OAuth2UsernamePasswordAuthenticationProvider->>AbstractOAuth2AuthenticationProvider: getPrincipal(request)
    AbstractOAuth2AuthenticationProvider->>AuthA: createUsernamePasswordAuth
    AuthA-->>AbstractOAuth2AuthenticationProvider: AuthA
    AbstractOAuth2AuthenticationProvider->>OAuth2AuthenticationProcessor: authentication(authA, request)

    alt authentication success
        OAuth2AuthenticationProcessor->>AuthA: getUserE
        OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: UsernamePasswordAuthenticationToken
        AbstractOAuth2AuthenticationProvider-->>OAuth2UsernamePasswordAuthenticationProvider: Authentication
        OAuth2UsernamePasswordAuthenticationProvider-->>Client: Authentication success
        OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent OK)
    else authentication GlobalException
        OAuth2AuthenticationProcessor->>LoginLogConvertor: toDomainEvent(request, authA, GlobalException)
        LoginLogConvertor->>AddressUtils: getRealAddress(ip)
        AddressUtils-->>LoginLogConvertor: address or throws InetAddressException or IOException or InterruptedException
        alt address resolution failure
            LoginLogConvertor-->>OAuth2AuthenticationProcessor: throws IllegalArgumentException
            OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent null)
            OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: GlobalException rethrown
        else address resolution success
            LoginLogConvertor-->>OAuth2AuthenticationProcessor: LoginEvent FAIL
            OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent FAIL)
            OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: GlobalException rethrown
        end
        AbstractOAuth2AuthenticationProvider-->>OAuth2UsernamePasswordAuthenticationProvider: propagate failure
        OAuth2UsernamePasswordAuthenticationProvider-->>Client: Authentication failure
    end
Loading

带内部异常处理的 AuthA 用户创建时序图

sequenceDiagram
    participant Caller
    participant AuthA
    participant RSAUtils
    participant AESUtils

    Caller->>AuthA: createUsernamePasswordAuth
    AuthA->>AuthA: getUserVByUsernamePasswordAuth
    AuthA->>RSAUtils: decryptByPrivateKey(usernameParam)
    RSAUtils-->>AuthA: username
    AuthA->>RSAUtils: decryptByPrivateKey(passwordParam)
    RSAUtils-->>AuthA: password
    AuthA->>AESUtils: encrypt(username)
    AESUtils-->>AuthA: encryptedUsername
    AuthA-->>AuthA: build UserV
    AuthA-->>Caller: AuthA with UserV

    note over AuthA: 在 getUserVByUsernamePasswordAuth 内部出现任意 Exception 时
    AuthA-->>Caller: throws IllegalArgumentException
Loading

更新后的认证域与基础设施异常处理类图

classDiagram
    class AuthA {
        <<Entity>>
        +GrantType grantType
        +CaptchaV captchaV
        +UserV userV
        +AuthA createUsernamePasswordAuth()
        +AuthA createMobileAuth()
        +AuthA createMailAuth()
        +AuthA createAuthorizationCodeAuth()
        +AuthA createTestAuth()
        -UserV getUserVByUsernamePasswordAuth()
        -UserV getUserVByAuthorizationCodeAuth()
        -UserV getUserVByMobileAuth()
        -UserV getUserVByMailAuth()
        -UserV getUserVByTestAuth()
        -AuthA create()
    }

    class OAuth2AuthenticationProcessor {
        -DomainEventPublisher kafkaDomainEventPublisher
        +UsernamePasswordAuthenticationToken authentication(AuthA authA, HttpServletRequest request)
    }

    class AbstractOAuth2AuthenticationProvider {
        -OAuth2AuthenticationProcessor authenticationProcessor
        +Authentication authentication(Authentication authentication, HttpServletRequest request)
        +UsernamePasswordAuthenticationToken authentication(AuthA authA, HttpServletRequest request)
        <<abstract>>
    }

    class OAuth2UsernamePasswordAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2MobileAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2MailAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2TestAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class LoginLogConvertor {
        +LoginLogCO toClientObject(LoginEvent loginEvent)
        +LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex)
    }

    class UserDetailsServiceImpl {
        +UserDetails loadUserByUsername(String username)
    }

    class DomainEventPublisher {
        +void publish(LoginEvent event)
    }

    class LoginEvent {
        +Long id
        +String username
        +String ip
        +String address
        +String browser
        +String os
        +int status
        +String errorMessage
        +int type
        +Long loginTime
        +Long tenantId
        +Long creator
        +Long deptId
    }

    class UserV {
        +String username()
        +String password()
        +String tenantCode()
        +String mail()
        +String mobile()
    }

    class UserE {
        +Long getId()
        +Long getTenantId()
        +Long getDeptId()
    }

    class GlobalException {
        +String getMsg()
    }

    class HttpServletRequest
    class Authentication
    class UsernamePasswordAuthenticationToken

    OAuth2UsernamePasswordAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2MobileAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2MailAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2TestAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider

    AbstractOAuth2AuthenticationProvider --> OAuth2AuthenticationProcessor
    OAuth2AuthenticationProcessor --> AuthA
    OAuth2AuthenticationProcessor --> DomainEventPublisher
    OAuth2AuthenticationProcessor --> LoginLogConvertor

    LoginLogConvertor --> AuthA
    LoginLogConvertor --> LoginEvent

    UserDetailsServiceImpl --> OAuth2AuthenticationProcessor
    UserDetailsServiceImpl --> AuthA
    UserDetailsServiceImpl --> UserV

    AuthA --> UserV
    AuthA --> UserE

    LoginEvent --> LoginLogConvertor
    GlobalException --> LoginLogConvertor
    HttpServletRequest --> LoginLogConvertor
    HttpServletRequest --> OAuth2AuthenticationProcessor
    Authentication --> AbstractOAuth2AuthenticationProvider
    UsernamePasswordAuthenticationToken --> AbstractOAuth2AuthenticationProvider
Loading

文件级变更

Change Details Files
为 AuthA 中用户值对象构建添加结构化异常处理和日志记录,并从其公共工厂方法中移除受检异常。
  • AuthA 添加 Lombok @Slf4j 注解以启用类级日志。
  • create*Auth 公共工厂方法中移除受检异常,使调用方不再需要 try/catchthrows 声明。
  • getUserVByUsernamePasswordAuthgetUserVByAuthorizationCodeAuthgetUserVByMobileAuthgetUserVByMailAuth 的方法体包裹在 try/catch 中,记录失败日志并重新抛出为 IllegalArgumentException 变体。
  • 简化 getUserVByTestAuth,让其委托给 getUserVByAuthorizationCodeAuth,且不再抛出受检异常。
laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java
通过显式异常处理和日志记录增强登录事件转换的健壮性,并通过去除受检异常简化 API。
  • LoginLogConvertor 添加 Lombok @Slf4j 注解以支持日志记录。
  • 修改 toDomainEvent,使其不再声明受检异常,而是将内部逻辑包裹在 try/catch 中。
  • 在 IP 地理位置解析过程中捕获 InetAddressExceptionIOExceptionInterruptedException,记录错误日志后重新抛出为 IllegalArgumentException
  • 将参数名从 ex 调整为 gex 以更清晰地表示其为 GlobalException,并相应更新相关使用。
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java
通过从方法签名中移除受检异常,并将错误处理下沉到更底层,简化认证处理器和认证提供者。
  • 更新 OAuth2AuthenticationProcessor.authentication,使其不再声明受检异常,并以 gex 形参名将 GlobalException 传入 LoginLogConvertor.toDomainEvent
  • 更新 AbstractOAuth2AuthenticationProvider.authentication,使其与更新后的 OAuth2AuthenticationProcessor 签名保持一致,不再 throws Exception
  • 更新 OAuth2MailAuthenticationProviderOAuth2MobileAuthenticationProviderOAuth2TestAuthenticationProviderOAuth2UsernamePasswordAuthenticationProvider 中的 getPrincipal 实现,从方法签名中移除 throws Exception
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MailAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MobileAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2TestAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2UsernamePasswordAuthenticationProvider.java
通过依赖底层认证流程的错误处理,而不是在本地捕获并转换异常,来简化 UserDetailsServiceImpl
  • 删除 loadUserByUsername 中围绕认证调用的外层 try/catch,让 GlobalException 和其他运行时异常向外传播。
  • 删除日志记录和 BizException 包装逻辑;错误现在由认证处理器和失败处理器统一处理。
  • 重新格式化主体提取逻辑,但保持原有行为:当 principal 为 User 时返回转换后的 UserDetails,否则回退为基于 UserV 构建的 Spring Security 基本 User
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java

提示与命令

与 Sourcery 交互

  • 触发新的代码审查: 在 Pull Request 中评论 @sourcery-ai review
  • 继续讨论: 直接回复 Sourcery 的审查评论。
  • 从审查评论生成 GitHub issue: 在某条审查评论下回复请求 Sourcery 从中创建 issue。你也可以直接回复 @sourcery-ai issue 从该评论生成 issue。
  • 生成 Pull Request 标题: 在 Pull Request 标题中任意位置写入 @sourcery-ai 以随时生成标题。也可以在 Pull Request 中评论 @sourcery-ai title 以(重新)生成标题。
  • 生成 Pull Request 总结: 在 Pull Request 正文任意位置写入 @sourcery-ai summary,即可在该位置生成 PR 总结。也可以在 Pull Request 中评论 @sourcery-ai summary 以(重新)生成总结。
  • 生成审查指导(reviewer's guide): 在 Pull Request 中评论 @sourcery-ai guide 可随时(重新)生成审查指南。
  • 一次性解决所有 Sourcery 评论: 在 Pull Request 中评论 @sourcery-ai resolve,将所有 Sourcery 评论标记为已解决。如果你已经处理完所有评论且不希望再看到它们时非常有用。
  • 批量驳回 Sourcery 审查: 在 Pull Request 中评论 @sourcery-ai dismiss,以驳回所有现有 Sourcery 审查。特别适用于你希望从一个全新的审查开始的情况——别忘了再评论 @sourcery-ai review 来触发新的审查!

自定义你的体验

访问你的 控制面板 来:

  • 启用或禁用诸如 Sourcery 生成的 Pull Request 总结、审查指南等审查功能。
  • 修改审查语言。
  • 添加、移除或编辑自定义审查说明。
  • 调整其他审查相关设置。

获取帮助

Original review guide in English

Reviewer's Guide

This PR refines exception handling and logging in the auth domain and infrastructure layers, especially around user creation and login logging, while simplifying method signatures by removing checked exceptions from authentication flows.

Sequence diagram for OAuth2 authentication flow with refined exception handling

sequenceDiagram
    actor Client
    participant OAuth2UsernamePasswordAuthenticationProvider
    participant AbstractOAuth2AuthenticationProvider
    participant OAuth2AuthenticationProcessor
    participant AuthA
    participant LoginLogConvertor
    participant AddressUtils
    participant DomainEventPublisher

    Client->>OAuth2UsernamePasswordAuthenticationProvider: authenticate
    OAuth2UsernamePasswordAuthenticationProvider->>AbstractOAuth2AuthenticationProvider: getPrincipal(request)
    AbstractOAuth2AuthenticationProvider->>AuthA: createUsernamePasswordAuth
    AuthA-->>AbstractOAuth2AuthenticationProvider: AuthA
    AbstractOAuth2AuthenticationProvider->>OAuth2AuthenticationProcessor: authentication(authA, request)

    alt authentication success
        OAuth2AuthenticationProcessor->>AuthA: getUserE
        OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: UsernamePasswordAuthenticationToken
        AbstractOAuth2AuthenticationProvider-->>OAuth2UsernamePasswordAuthenticationProvider: Authentication
        OAuth2UsernamePasswordAuthenticationProvider-->>Client: Authentication success
        OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent OK)
    else authentication GlobalException
        OAuth2AuthenticationProcessor->>LoginLogConvertor: toDomainEvent(request, authA, GlobalException)
        LoginLogConvertor->>AddressUtils: getRealAddress(ip)
        AddressUtils-->>LoginLogConvertor: address or throws InetAddressException or IOException or InterruptedException
        alt address resolution failure
            LoginLogConvertor-->>OAuth2AuthenticationProcessor: throws IllegalArgumentException
            OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent null)
            OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: GlobalException rethrown
        else address resolution success
            LoginLogConvertor-->>OAuth2AuthenticationProcessor: LoginEvent FAIL
            OAuth2AuthenticationProcessor->>DomainEventPublisher: publish(LoginEvent FAIL)
            OAuth2AuthenticationProcessor-->>AbstractOAuth2AuthenticationProvider: GlobalException rethrown
        end
        AbstractOAuth2AuthenticationProvider-->>OAuth2UsernamePasswordAuthenticationProvider: propagate failure
        OAuth2UsernamePasswordAuthenticationProvider-->>Client: Authentication failure
    end
Loading

Sequence diagram for AuthA user creation with internal exception handling

sequenceDiagram
    participant Caller
    participant AuthA
    participant RSAUtils
    participant AESUtils

    Caller->>AuthA: createUsernamePasswordAuth
    AuthA->>AuthA: getUserVByUsernamePasswordAuth
    AuthA->>RSAUtils: decryptByPrivateKey(usernameParam)
    RSAUtils-->>AuthA: username
    AuthA->>RSAUtils: decryptByPrivateKey(passwordParam)
    RSAUtils-->>AuthA: password
    AuthA->>AESUtils: encrypt(username)
    AESUtils-->>AuthA: encryptedUsername
    AuthA-->>AuthA: build UserV
    AuthA-->>Caller: AuthA with UserV

    note over AuthA: On any Exception inside getUserVByUsernamePasswordAuth
    AuthA-->>Caller: throws IllegalArgumentException
Loading

Updated class diagram for auth domain and infrastructure exception handling

classDiagram
    class AuthA {
        <<Entity>>
        +GrantType grantType
        +CaptchaV captchaV
        +UserV userV
        +AuthA createUsernamePasswordAuth()
        +AuthA createMobileAuth()
        +AuthA createMailAuth()
        +AuthA createAuthorizationCodeAuth()
        +AuthA createTestAuth()
        -UserV getUserVByUsernamePasswordAuth()
        -UserV getUserVByAuthorizationCodeAuth()
        -UserV getUserVByMobileAuth()
        -UserV getUserVByMailAuth()
        -UserV getUserVByTestAuth()
        -AuthA create()
    }

    class OAuth2AuthenticationProcessor {
        -DomainEventPublisher kafkaDomainEventPublisher
        +UsernamePasswordAuthenticationToken authentication(AuthA authA, HttpServletRequest request)
    }

    class AbstractOAuth2AuthenticationProvider {
        -OAuth2AuthenticationProcessor authenticationProcessor
        +Authentication authentication(Authentication authentication, HttpServletRequest request)
        +UsernamePasswordAuthenticationToken authentication(AuthA authA, HttpServletRequest request)
        <<abstract>>
    }

    class OAuth2UsernamePasswordAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2MobileAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2MailAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class OAuth2TestAuthenticationProvider {
        +boolean supports(Class authentication)
        +Authentication getPrincipal(HttpServletRequest request)
    }

    class LoginLogConvertor {
        +LoginLogCO toClientObject(LoginEvent loginEvent)
        +LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex)
    }

    class UserDetailsServiceImpl {
        +UserDetails loadUserByUsername(String username)
    }

    class DomainEventPublisher {
        +void publish(LoginEvent event)
    }

    class LoginEvent {
        +Long id
        +String username
        +String ip
        +String address
        +String browser
        +String os
        +int status
        +String errorMessage
        +int type
        +Long loginTime
        +Long tenantId
        +Long creator
        +Long deptId
    }

    class UserV {
        +String username()
        +String password()
        +String tenantCode()
        +String mail()
        +String mobile()
    }

    class UserE {
        +Long getId()
        +Long getTenantId()
        +Long getDeptId()
    }

    class GlobalException {
        +String getMsg()
    }

    class HttpServletRequest
    class Authentication
    class UsernamePasswordAuthenticationToken

    OAuth2UsernamePasswordAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2MobileAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2MailAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider
    OAuth2TestAuthenticationProvider --|> AbstractOAuth2AuthenticationProvider

    AbstractOAuth2AuthenticationProvider --> OAuth2AuthenticationProcessor
    OAuth2AuthenticationProcessor --> AuthA
    OAuth2AuthenticationProcessor --> DomainEventPublisher
    OAuth2AuthenticationProcessor --> LoginLogConvertor

    LoginLogConvertor --> AuthA
    LoginLogConvertor --> LoginEvent

    UserDetailsServiceImpl --> OAuth2AuthenticationProcessor
    UserDetailsServiceImpl --> AuthA
    UserDetailsServiceImpl --> UserV

    AuthA --> UserV
    AuthA --> UserE

    LoginEvent --> LoginLogConvertor
    GlobalException --> LoginLogConvertor
    HttpServletRequest --> LoginLogConvertor
    HttpServletRequest --> OAuth2AuthenticationProcessor
    Authentication --> AbstractOAuth2AuthenticationProvider
    UsernamePasswordAuthenticationToken --> AbstractOAuth2AuthenticationProvider
Loading

File-Level Changes

Change Details Files
Add structured exception handling and logging for user value construction in AuthA and remove checked exceptions from its public factory methods.
  • Annotate AuthA with Lombok @slf4j to enable class-level logging.
  • Remove checked exceptions from create*Auth public factory methods so callers no longer need try/catch or throws clauses.
  • Wrap getUserVByUsernamePasswordAuth, getUserVByAuthorizationCodeAuth, getUserVByMobileAuth, and getUserVByMailAuth bodies in try/catch blocks, logging failures and rethrowing as IllegalArgumentException variants.
  • Simplify getUserVByTestAuth to delegate to getUserVByAuthorizationCodeAuth without throwing checked exceptions.
laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java
Harden login event conversion with explicit exception handling and logging, and simplify the API by eliminating checked exceptions.
  • Annotate LoginLogConvertor with Lombok @slf4j for logging support.
  • Change toDomainEvent to no longer declare checked exceptions and instead wrap its logic in a try/catch.
  • Catch InetAddressException, IOException, and InterruptedException during IP geolocation and rethrow as IllegalArgumentException after logging the error.
  • Adjust parameter name from ex to gex to clarify it is a GlobalException and update usages accordingly.
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java
Simplify the authentication processor and providers by removing checked exceptions from method signatures and centralizing error handling in lower layers.
  • Update OAuth2AuthenticationProcessor.authentication to not declare checked exceptions and to pass GlobalException as gex to LoginLogConvertor.toDomainEvent.
  • Update AbstractOAuth2AuthenticationProvider.authentication to match the updated OAuth2AuthenticationProcessor signature without throws Exception.
  • Update getPrincipal implementations in OAuth2MailAuthenticationProvider, OAuth2MobileAuthenticationProvider, OAuth2TestAuthenticationProvider, and OAuth2UsernamePasswordAuthenticationProvider to drop throws Exception from their signatures.
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MailAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MobileAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2TestAuthenticationProvider.java
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2UsernamePasswordAuthenticationProvider.java
Simplify UserDetailsServiceImpl by relying on the underlying authentication flow for error handling instead of catching and translating exceptions locally.
  • Remove the outer try/catch around the authentication call in loadUserByUsername, letting GlobalException and other runtime exceptions propagate.
  • Delete logging and BizException wrapping logic; errors are now handled by the authentication processor and failure handlers.
  • Reformat the principal extraction logic but keep the behavior: return converted UserDetails when principal is a User, otherwise fall back to a basic Spring Security User built from UserV.
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@KouShenhai KouShenhai merged commit 1bb45f6 into master Mar 20, 2026
13 of 16 checks passed
@qodo-code-review
Copy link

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Review Summary by Qodo

Refactor exception handling and improve error logging in authentication module

✨ Enhancement 🐞 Bug fix

Grey Divider

Walkthroughs

Description
• Remove checked exceptions from method signatures across authentication flow
• Add proper exception handling with try-catch blocks and logging
• Refactor exception handling in UserDetailsServiceImpl to remove unnecessary wrapping
• Add @Slf4j annotation for logging in AuthA and LoginLogConvertor classes
• Remove unused @Component annotation from OAuth2AuthenticationFailureHandler
Diagram
flowchart LR
  A["Method Signatures"] -->|Remove throws Exception| B["Clean API"]
  C["Exception Handling"] -->|Add try-catch blocks| D["Internal Error Management"]
  E["Logging"] -->|Add @Slf4j annotation| F["Better Observability"]
  B --> G["Improved Code Quality"]
  D --> G
  F --> G
Loading

Grey Divider

File Changes

1. laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java Enhancement, error handling +72/-48

Remove throws Exception and add internal error handling

laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java


2. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/OAuth2AuthenticationFailureHandler.java Miscellaneous +0/-1

Remove unused @component annotation

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/OAuth2AuthenticationFailureHandler.java


3. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java ✨ Enhancement +1/-2

Remove throws Exception from authentication method

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java


View more (7)
4. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java Formatting, enhancement +5/-5

Improve exception variable naming and formatting

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java


5. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MailAuthenticationProvider.java ✨ Enhancement +1/-1

Remove throws Exception from getPrincipal method

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MailAuthenticationProvider.java


6. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MobileAuthenticationProvider.java ✨ Enhancement +1/-1

Remove throws Exception from getPrincipal method

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MobileAuthenticationProvider.java


7. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2TestAuthenticationProvider.java ✨ Enhancement +1/-1

Remove throws Exception from getPrincipal method

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2TestAuthenticationProvider.java


8. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2UsernamePasswordAuthenticationProvider.java ✨ Enhancement +1/-1

Remove throws Exception from getPrincipal method

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2UsernamePasswordAuthenticationProvider.java


9. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java Bug fix, enhancement +9/-17

Simplify exception handling and remove unnecessary try-catch

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java


10. laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java Error handling, enhancement +38/-29

Add logging and wrap exception-throwing code in try-catch

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java


Grey Divider

Qodo Logo

@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: d2440fb8-57ba-434b-8f04-1d100afa6b4d

📥 Commits

Reviewing files that changed from the base of the PR and between 8f1e59d and cc742e0.

📒 Files selected for processing (10)
  • laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/OAuth2AuthenticationFailureHandler.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MailAuthenticationProvider.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2MobileAuthenticationProvider.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2TestAuthenticationProvider.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2UsernamePasswordAuthenticationProvider.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java
  • laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java

Walkthrough

This PR systematically removes throws Exception declarations from authentication and domain model method signatures across the auth module. Exception handling logic is refactored—helper methods now wrap operations with try/catch blocks that convert checked exceptions to unchecked exceptions, while provider methods rely on their implementations' error propagation.

Changes

Cohort / File(s) Summary
Domain Model Exception Handling
laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java
Added @Slf4j logging. Removed throws Exception from 5 public factory methods (createUsernamePasswordAuth, createMobileAuth, createMailAuth, createAuthorizationCodeAuth, createTestAuth). Wrapped private helper methods with try/catch blocks that log errors and rethrow as IllegalArgumentException.
Infrastructure Import Cleanup
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/OAuth2AuthenticationFailureHandler.java
Removed unused @Component import; no functional changes.
Authentication Provider Signatures
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2*.../OAuth2MailAuthenticationProvider.java, OAuth2MobileAuthenticationProvider.java, OAuth2TestAuthenticationProvider.java, OAuth2UsernamePasswordAuthenticationProvider.java
Removed throws Exception from getPrincipal(HttpServletRequest request) method signatures across four provider implementations; method bodies unchanged.
Authentication Processing Chain
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java, OAuth2AuthenticationProcessor.java
Removed throws Exception from authentication(...) method signatures. Refactored parameter formatting in OAuth2AuthenticationProcessor; renamed exception variable from ex to gex.
User Details Service
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/UserDetailsServiceImpl.java
Removed explicit try/catch-based exception wrapping; simplified flow to call authentication processor directly and convert result to UserDetails.
Login Event Logging
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java
Added @Slf4j logging. Removed throws Exception from toDomainEvent(...) method. Wrapped method body with try/catch to handle InetAddressException, IOException, and InterruptedException, logging and rethrowing as IllegalArgumentException.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • #3145: Modifies org.laokou.auth.model.AuthA with logging and exception handling adjustments that overlap with this PR's domain model changes.
  • #5398: Updates the same AuthA class, with Javadoc changes to related fields.
  • #5234: Introduces methods in AuthA that are directly modified by this PR's exception handling refactor.

Suggested labels

Review effort 4/5

Suggested reviewers

  • sourcery-ai

Poem

🐰 Hops through the code with care and grace,
Removing throws from every place,
Try-catch shields now hold the line,
Exceptions wrapped, more clean and fine!
Auth flows forward, safe and bright,
Checked to unchecked—a rabbit's delight!

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch dev
📝 Coding Plan
  • Generate coding plan for human review comments

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 OpenGrep (1.16.4)
laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java

┌──────────────┐
│ Opengrep CLI │
└──────────────┘

�[32m✔�[39m �[1mOpengrep OSS�[0m
�[32m✔�[39m Basic security coverage for first-party code vulnerabilities.

�[1m Loading rules from local config...�[0m

  • 6 others

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - 我发现了两个问题,并给出了一些整体性的反馈:

  • AuthA 中新的异常处理逻辑(例如 getUserVByUsernamePasswordAuthgetUserVByMailAuth 等),建议保留原始异常原因,而不是仅使用 ex.getMessage() 抛出 IllegalArgumentException,这样调用方可以更准确地检查底层异常及其堆栈信息。
  • LoginLogConvertor.toDomainEvent 方法现在在地址解析失败时抛出 IllegalArgumentException;你可能会希望在这里记录错误日志,并回退到一个默认地址,这样临时性的 IP 查询问题就不会中断登录流程/事件创建。
  • 对于加解密以及 IO/IP 查询路径中的失败,使用 IllegalArgumentException 在语义上略显误导;可以考虑使用更贴近业务语义的运行时异常(或者复用 GlobalException / BizException),以更好地表达这些失败的性质。
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the new exception handling in `AuthA` (e.g., `getUserVByUsernamePasswordAuth`, `getUserVByMailAuth`, etc.), consider preserving the original cause instead of throwing `IllegalArgumentException` with only `ex.getMessage()`, so callers can inspect the underlying exception and stack trace more accurately.
- The `LoginLogConvertor.toDomainEvent` method now throws `IllegalArgumentException` when address resolution fails; you might want to log the error and fall back to a default address instead, so a transient IP lookup issue doesn’t break the login flow/event creation.
- Using `IllegalArgumentException` for failures in cryptographic/decryption and IO/IP lookup paths is a bit misleading semantically; consider using a more domain-appropriate runtime exception (or reusing `GlobalException`/`BizException`) to better express the nature of these failures.

## Individual Comments

### Comment 1
<location path="laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java" line_range="471-473" />
<code_context>
-			.mail(AESUtils.encrypt(this.captchaV.uuid()))
-			.mobile(StringConstants.EMPTY)
-			.build();
+	private UserV getUserVByAuthorizationCodeAuth() {
+		try {
+			String username = getParameterValue(Constants.USERNAME);
+			String password = getParameterValue(Constants.PASSWORD);
+			String tenantCode = getParameterValue(Constants.TENANT_CODE);
+			return UserV.builder()
+				.username(AESUtils.encrypt(username))
+				.password(password)
+				.tenantCode(tenantCode)
+				.mail(StringConstants.EMPTY)
+				.mobile(StringConstants.EMPTY)
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
</code_context>
<issue_to_address>
**suggestion (bug_risk):** InterruptedException (and other checked errors) are treated as IllegalArgumentException, and the thread is not re-interrupted.

This method wraps all `Exception`s in `IllegalArgumentException(ex.getMessage())`, losing the original cause and any interrupted status. If `InterruptedException` (or other non-programming errors) can be thrown, the current thread should be re-interrupted and the cause preserved. Consider calling `Thread.currentThread().interrupt();` before rethrowing and using a more suitable runtime exception that wraps the original cause (e.g., `new RuntimeException("Failed to build UserV for authorization code auth", ex)`).

```suggestion
		catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
			log.error("getUserVByAuthorizationCodeAuth interrupted: {}", ex.getMessage(), ex);
			throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
		}
		catch (Exception ex) {
			log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
			throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
```
</issue_to_address>

### Comment 2
<location path="laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java" line_range="106-115" />
<code_context>
+	public static LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex) {
</code_context>
<issue_to_address>
**issue (bug_risk):** `toDomainEvent` now throws `IllegalArgumentException` on infrastructure issues, which can misclassify failures and drop interruption status.

Wrapping `InetAddressException`, `IOException`, and `InterruptedException` in `IllegalArgumentException(ex.getMessage())` both mislabels infrastructure/IO failures as argument issues and drops the original cause. It also swallows `InterruptedException` without restoring the interrupt flag.

Consider instead:
- Preserving the cause, e.g. `throw new RuntimeException("Failed to build LoginEvent", ex);` or a domain-specific exception.
- If interruption matters here, call `Thread.currentThread().interrupt();` before rethrowing.

This preserves logging while giving callers clearer error signals and respecting cooperative cancellation.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
Original comment in English

Hey - I've found 2 issues, and left some high level feedback:

  • In the new exception handling in AuthA (e.g., getUserVByUsernamePasswordAuth, getUserVByMailAuth, etc.), consider preserving the original cause instead of throwing IllegalArgumentException with only ex.getMessage(), so callers can inspect the underlying exception and stack trace more accurately.
  • The LoginLogConvertor.toDomainEvent method now throws IllegalArgumentException when address resolution fails; you might want to log the error and fall back to a default address instead, so a transient IP lookup issue doesn’t break the login flow/event creation.
  • Using IllegalArgumentException for failures in cryptographic/decryption and IO/IP lookup paths is a bit misleading semantically; consider using a more domain-appropriate runtime exception (or reusing GlobalException/BizException) to better express the nature of these failures.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- In the new exception handling in `AuthA` (e.g., `getUserVByUsernamePasswordAuth`, `getUserVByMailAuth`, etc.), consider preserving the original cause instead of throwing `IllegalArgumentException` with only `ex.getMessage()`, so callers can inspect the underlying exception and stack trace more accurately.
- The `LoginLogConvertor.toDomainEvent` method now throws `IllegalArgumentException` when address resolution fails; you might want to log the error and fall back to a default address instead, so a transient IP lookup issue doesn’t break the login flow/event creation.
- Using `IllegalArgumentException` for failures in cryptographic/decryption and IO/IP lookup paths is a bit misleading semantically; consider using a more domain-appropriate runtime exception (or reusing `GlobalException`/`BizException`) to better express the nature of these failures.

## Individual Comments

### Comment 1
<location path="laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java" line_range="471-473" />
<code_context>
-			.mail(AESUtils.encrypt(this.captchaV.uuid()))
-			.mobile(StringConstants.EMPTY)
-			.build();
+	private UserV getUserVByAuthorizationCodeAuth() {
+		try {
+			String username = getParameterValue(Constants.USERNAME);
+			String password = getParameterValue(Constants.PASSWORD);
+			String tenantCode = getParameterValue(Constants.TENANT_CODE);
+			return UserV.builder()
+				.username(AESUtils.encrypt(username))
+				.password(password)
+				.tenantCode(tenantCode)
+				.mail(StringConstants.EMPTY)
+				.mobile(StringConstants.EMPTY)
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
</code_context>
<issue_to_address>
**suggestion (bug_risk):** InterruptedException (and other checked errors) are treated as IllegalArgumentException, and the thread is not re-interrupted.

This method wraps all `Exception`s in `IllegalArgumentException(ex.getMessage())`, losing the original cause and any interrupted status. If `InterruptedException` (or other non-programming errors) can be thrown, the current thread should be re-interrupted and the cause preserved. Consider calling `Thread.currentThread().interrupt();` before rethrowing and using a more suitable runtime exception that wraps the original cause (e.g., `new RuntimeException("Failed to build UserV for authorization code auth", ex)`).

```suggestion
		catch (InterruptedException ex) {
			Thread.currentThread().interrupt();
			log.error("getUserVByAuthorizationCodeAuth interrupted: {}", ex.getMessage(), ex);
			throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
		}
		catch (Exception ex) {
			log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
			throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
```
</issue_to_address>

### Comment 2
<location path="laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java" line_range="106-115" />
<code_context>
+	public static LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex) {
</code_context>
<issue_to_address>
**issue (bug_risk):** `toDomainEvent` now throws `IllegalArgumentException` on infrastructure issues, which can misclassify failures and drop interruption status.

Wrapping `InetAddressException`, `IOException`, and `InterruptedException` in `IllegalArgumentException(ex.getMessage())` both mislabels infrastructure/IO failures as argument issues and drops the original cause. It also swallows `InterruptedException` without restoring the interrupt flag.

Consider instead:
- Preserving the cause, e.g. `throw new RuntimeException("Failed to build LoginEvent", ex);` or a domain-specific exception.
- If interruption matters here, call `Thread.currentThread().interrupt();` before rethrowing.

This preserves logging while giving callers clearer error signals and respecting cooperative cancellation.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +471 to +473
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (bug_risk): InterruptedException(以及其他受检异常)被当作 IllegalArgumentException 处理,而且线程不会被重新设置中断标记。

该方法将所有 Exception 都包装成 IllegalArgumentException(ex.getMessage()),从而丢失了原始异常原因以及任何中断状态。如果这里可能抛出 InterruptedException(或其他非编程错误),则应在重新抛出之前重新设置当前线程的中断标记,并保留原始异常作为 cause。可以考虑在重新抛出前调用 Thread.currentThread().interrupt();,并使用更合适的运行时异常来包装原始异常(例如:new RuntimeException("Failed to build UserV for authorization code auth", ex))。

Suggested change
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
log.error("getUserVByAuthorizationCodeAuth interrupted: {}", ex.getMessage(), ex);
throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
}
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
Original comment in English

suggestion (bug_risk): InterruptedException (and other checked errors) are treated as IllegalArgumentException, and the thread is not re-interrupted.

This method wraps all Exceptions in IllegalArgumentException(ex.getMessage()), losing the original cause and any interrupted status. If InterruptedException (or other non-programming errors) can be thrown, the current thread should be re-interrupted and the cause preserved. Consider calling Thread.currentThread().interrupt(); before rethrowing and using a more suitable runtime exception that wraps the original cause (e.g., new RuntimeException("Failed to build UserV for authorization code auth", ex)).

Suggested change
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
catch (InterruptedException ex) {
Thread.currentThread().interrupt();
log.error("getUserVByAuthorizationCodeAuth interrupted: {}", ex.getMessage(), ex);
throw new RuntimeException("Failed to build UserV for authorization code auth", ex);
}
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new RuntimeException("Failed to build UserV for authorization code auth", ex);

Comment on lines +106 to +115
public static LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex) {
try {
Capabilities capabilities = RequestUtils.getCapabilities(request);
String ip = IpUtils.getIpAddr(request);
int status = LoginStatus.OK.getCode();
UserE userE = authA.getUserE();
Optional<UserE> optional = Optional.ofNullable(userE);
Long creator = optional.map(UserE::getId).orElse(null);
Long tenantId = optional.map(UserE::getTenantId).orElse(null);
Long deptId = optional.map(UserE::getDeptId).orElse(null);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): toDomainEvent 现在在出现基础设施层问题时抛出 IllegalArgumentException,这可能会导致错误被错误分类,并且丢失中断状态。

InetAddressExceptionIOExceptionInterruptedException 包装成 IllegalArgumentException(ex.getMessage()),既把基础设施/IO 失败误标记为参数错误,又丢失了原始异常原因。同时还吞掉了 InterruptedException,而没有恢复中断标记。

可以考虑:

  • 保留原始 cause,例如 throw new RuntimeException("Failed to build LoginEvent", ex);,或者使用一个领域特定的异常;
  • 如果这里的中断语义很重要,在重新抛出前调用 Thread.currentThread().interrupt();

这样既能保留日志,又能为调用方提供更清晰的错误信号,并遵守协作式取消的约定。

Original comment in English

issue (bug_risk): toDomainEvent now throws IllegalArgumentException on infrastructure issues, which can misclassify failures and drop interruption status.

Wrapping InetAddressException, IOException, and InterruptedException in IllegalArgumentException(ex.getMessage()) both mislabels infrastructure/IO failures as argument issues and drops the original cause. It also swallows InterruptedException without restoring the interrupt flag.

Consider instead:

  • Preserving the cause, e.g. throw new RuntimeException("Failed to build LoginEvent", ex); or a domain-specific exception.
  • If interruption matters here, call Thread.currentThread().interrupt(); before rethrowing.

This preserves logging while giving callers clearer error signals and respecting cooperative cancellation.

@sonarqubecloud
Copy link

Quality Gate Failed Quality Gate failed

Failed conditions
C Reliability Rating on New Code (required ≥ A)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

@qodo-code-review
Copy link

ⓘ You are approaching your monthly quota for Qodo. Upgrade your plan

Code Review by Qodo

🐞 Bugs (2) 📘 Rule violations (0) 📎 Requirement gaps (0) 📐 Spec deviations (0)

Grey Divider


Action required

1. GlobalException masked as IAE 🐞 Bug ✓ Correctness
Description
AuthA now catches exceptions from RSA/AES operations and rethrows IllegalArgumentException, which
converts GlobalException/SystemException into a non-GlobalException and bypasses OAuth2 error
translation. As a result, malformed/invalid encrypted credentials can surface as generic
RuntimeException/500 instead of a structured OAuth2/GlobalException response.
Code

laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java[R435-504]

+	private UserV getUserVByUsernamePasswordAuth() {
+		try {
+			String username = RSAUtils.decryptByPrivateKey(getParameterValue(Constants.USERNAME));
+			String password = RSAUtils.decryptByPrivateKey(getParameterValue(Constants.PASSWORD));
+			String tenantCode = getParameterValue(Constants.TENANT_CODE);
+			return UserV.builder()
+				.username(AESUtils.encrypt(username))
+				.password(password)
+				.tenantCode(tenantCode)
+				.mail(StringConstants.EMPTY)
+				.mobile(StringConstants.EMPTY)
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByUsernamePasswordAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
+		}
	}

-	private UserV getUserVByTestAuth() throws Exception {
+	private UserV getUserVByTestAuth() {
		return getUserVByAuthorizationCodeAuth();
	}

-	private UserV getUserVByAuthorizationCodeAuth() throws Exception {
-		String username = getParameterValue(Constants.USERNAME);
-		String password = getParameterValue(Constants.PASSWORD);
-		String tenantCode = getParameterValue(Constants.TENANT_CODE);
-		return UserV.builder()
-			.username(AESUtils.encrypt(username))
-			.password(password)
-			.tenantCode(tenantCode)
-			.mail(StringConstants.EMPTY)
-			.mobile(StringConstants.EMPTY)
-			.build();
-	}
-
-	private UserV getUserVByMobileAuth() throws Exception {
-		String tenantCode = getParameterValue(Constants.TENANT_CODE);
-		return UserV.builder()
-			.username(StringConstants.EMPTY)
-			.tenantCode(tenantCode)
-			.mail(StringConstants.EMPTY)
-			.mobile(AESUtils.encrypt(this.captchaV.uuid()))
-			.build();
-	}
-
-	private UserV getUserVByMailAuth() throws Exception {
-		String tenantCode = getParameterValue(Constants.TENANT_CODE);
-		return UserV.builder()
-			.username(StringConstants.EMPTY)
-			.tenantCode(tenantCode)
-			.mail(AESUtils.encrypt(this.captchaV.uuid()))
-			.mobile(StringConstants.EMPTY)
-			.build();
+	private UserV getUserVByAuthorizationCodeAuth() {
+		try {
+			String username = getParameterValue(Constants.USERNAME);
+			String password = getParameterValue(Constants.PASSWORD);
+			String tenantCode = getParameterValue(Constants.TENANT_CODE);
+			return UserV.builder()
+				.username(AESUtils.encrypt(username))
+				.password(password)
+				.tenantCode(tenantCode)
+				.mail(StringConstants.EMPTY)
+				.mobile(StringConstants.EMPTY)
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
+		}
+	}
+
+	private UserV getUserVByMobileAuth() {
+		try {
+			return UserV.builder()
+				.username(StringConstants.EMPTY)
+				.tenantCode(getParameterValue(Constants.TENANT_CODE))
+				.mail(StringConstants.EMPTY)
+				.mobile(AESUtils.encrypt(this.captchaV.uuid()))
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByMobileAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex);
+		}
+	}
+
+	private UserV getUserVByMailAuth() {
+		try {
+			return UserV.builder()
+				.username(StringConstants.EMPTY)
+				.tenantCode(getParameterValue(Constants.TENANT_CODE))
+				.mail(AESUtils.encrypt(this.captchaV.uuid()))
+				.mobile(StringConstants.EMPTY)
+				.build();
+		}
+		catch (Exception ex) {
+			log.error("getUserVByMailAuth error: {}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
+		}
Evidence
RSAUtils.decryptByPrivateKey already throws a SystemException (which is a GlobalException) on
decrypt failure; AuthA catches it as a generic Exception and rethrows IllegalArgumentException,
losing the GlobalException type. AbstractOAuth2AuthenticationProvider only translates
GlobalException into an OAuth2AuthenticationException; other exceptions fall into the generic catch
and are wrapped as RuntimeException, changing the externally observed error behavior.

laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java[435-504]
laokou-common/laokou-common-crypto/src/main/java/org/laokou/common/crypto/util/RSAUtils.java[93-101]
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/AbstractOAuth2AuthenticationProvider.java[93-108]
laokou-common/laokou-common-crypto/src/main/java/org/laokou/common/crypto/util/AESUtils.java[72-88]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`AuthA` converts `GlobalException`/`SystemException` (e.g., from `RSAUtils.decryptByPrivateKey`) into `IllegalArgumentException`. This breaks the downstream exception translation that relies on `GlobalException` and can turn normal auth failures into generic 500s.

## Issue Context
- `RSAUtils.decryptByPrivateKey(...)` throws `SystemException` (a `GlobalException`) on decrypt failure.
- `AbstractOAuth2AuthenticationProvider.authenticate(...)` only converts `GlobalException` into an `OAuth2AuthenticationException`; other exceptions are wrapped into a `RuntimeException`.

## Fix Focus Areas
- Ensure `GlobalException` is rethrown unchanged (do not wrap).
- For non-Global exceptions, wrap into a `SystemException`/`BizException` with an appropriate code/message and preserve the cause (e.g., `new SystemException(code, msg, ex)`), rather than `IllegalArgumentException(ex.getMessage())`.
- Keep the original exception as the cause to preserve stack traces.

### Focus lines
- laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java[435-504]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. Login depends on IP lookup 🐞 Bug ⛯ Reliability
Description
LoginLogConvertor.toDomainEvent now rethrows IllegalArgumentException on address/IP lookup failures
(including InterruptedException), and OAuth2AuthenticationProcessor calls it on the success path
before returning the authentication token. A transient geo/IP lookup failure can therefore abort an
otherwise successful login and the InterruptedException handling clears the interrupt flag.
Code

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java[R106-140]

+	public static LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex) {
+		try {
+			Capabilities capabilities = RequestUtils.getCapabilities(request);
+			String ip = IpUtils.getIpAddr(request);
+			int status = LoginStatus.OK.getCode();
+			UserE userE = authA.getUserE();
+			Optional<UserE> optional = Optional.ofNullable(userE);
+			Long creator = optional.map(UserE::getId).orElse(null);
+			Long tenantId = optional.map(UserE::getTenantId).orElse(null);
+			Long deptId = optional.map(UserE::getDeptId).orElse(null);
+			String errorMessage = StringConstants.EMPTY;
+			if (ObjectUtils.isNotNull(gex)) {
+				status = LoginStatus.FAIL.getCode();
+				errorMessage = gex.getMsg();
+			}
+			return LoginEvent.builder()
+				.id(authA.getId())
+				.username(authA.getLoginName())
+				.ip(ip)
+				.address(AddressUtils.getRealAddress(ip))
+				.browser(capabilities.getBrowser())
+				.os(capabilities.getPlatform())
+				.status(status)
+				.errorMessage(errorMessage)
+				.type(authA.getGrantType().getCode())
+				.loginTime(authA.getCreateTime())
+				.tenantId(tenantId)
+				.creator(creator)
+				.deptId(deptId)
+				.build();
+		}
+		catch (InetAddressException | IOException | InterruptedException ex) {
+			log.error("错误信息:{}", ex.getMessage(), ex);
+			throw new IllegalArgumentException(ex.getMessage());
		}
-		return LoginEvent.builder()
-			.id(authA.getId())
-			.username(authA.getLoginName())
-			.ip(ip)
-			.address(AddressUtils.getRealAddress(ip))
-			.browser(capabilities.getBrowser())
-			.os(capabilities.getPlatform())
-			.status(status)
-			.errorMessage(errorMessage)
-			.type(authA.getGrantType().getCode())
-			.loginTime(authA.getCreateTime())
-			.tenantId(tenantId)
-			.creator(creator)
-			.deptId(deptId)
-			.build();
Evidence
OAuth2AuthenticationProcessor calls LoginLogConvertor.toDomainEvent() after
domainService.auth(authA) and before returning the UsernamePasswordAuthenticationToken; if
toDomainEvent throws (now IllegalArgumentException), the whole authentication fails.
AddressUtils.getRealAddress is explicitly declared to throw
InetAddressException/IOException/InterruptedException, and the new catch rethrows without restoring
interrupt status.

laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java[48-69]
laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java[106-140]
laokou-common/laokou-common-core/src/main/java/org/laokou/common/core/util/AddressUtils.java[92-94]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`LoginLogConvertor.toDomainEvent(...)` throws `IllegalArgumentException` when IP-&gt;address resolution fails, and it catches `InterruptedException` without restoring interrupt status. Because the auth processor calls `toDomainEvent` on the success path, a transient lookup failure can break successful authentication.

## Issue Context
- `OAuth2AuthenticationProcessor.authentication(...)` calls `LoginLogConvertor.toDomainEvent(request, authA, null)` before returning the token.
- `AddressUtils.getRealAddress(...)` declares `throws InetAddressException, IOException, InterruptedException`.

## Fix Focus Areas
- Do not throw from `toDomainEvent` for address/capabilities lookup failures; instead:
 - Log the failure
 - Use safe defaults (e.g., empty/&quot;unknown&quot; address/browser/os)
 - Still return a `LoginEvent`
- If `InterruptedException` is caught, call `Thread.currentThread().interrupt()` before continuing/returning.
- Preserve causes if you must rethrow, and prefer a domain-specific `GlobalException` rather than `IllegalArgumentException`.

### Focus lines
- laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java[106-140]
- laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java[48-69]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

Comment on lines +435 to +504
private UserV getUserVByUsernamePasswordAuth() {
try {
String username = RSAUtils.decryptByPrivateKey(getParameterValue(Constants.USERNAME));
String password = RSAUtils.decryptByPrivateKey(getParameterValue(Constants.PASSWORD));
String tenantCode = getParameterValue(Constants.TENANT_CODE);
return UserV.builder()
.username(AESUtils.encrypt(username))
.password(password)
.tenantCode(tenantCode)
.mail(StringConstants.EMPTY)
.mobile(StringConstants.EMPTY)
.build();
}
catch (Exception ex) {
log.error("getUserVByUsernamePasswordAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
}
}

private UserV getUserVByTestAuth() throws Exception {
private UserV getUserVByTestAuth() {
return getUserVByAuthorizationCodeAuth();
}

private UserV getUserVByAuthorizationCodeAuth() throws Exception {
String username = getParameterValue(Constants.USERNAME);
String password = getParameterValue(Constants.PASSWORD);
String tenantCode = getParameterValue(Constants.TENANT_CODE);
return UserV.builder()
.username(AESUtils.encrypt(username))
.password(password)
.tenantCode(tenantCode)
.mail(StringConstants.EMPTY)
.mobile(StringConstants.EMPTY)
.build();
}

private UserV getUserVByMobileAuth() throws Exception {
String tenantCode = getParameterValue(Constants.TENANT_CODE);
return UserV.builder()
.username(StringConstants.EMPTY)
.tenantCode(tenantCode)
.mail(StringConstants.EMPTY)
.mobile(AESUtils.encrypt(this.captchaV.uuid()))
.build();
}

private UserV getUserVByMailAuth() throws Exception {
String tenantCode = getParameterValue(Constants.TENANT_CODE);
return UserV.builder()
.username(StringConstants.EMPTY)
.tenantCode(tenantCode)
.mail(AESUtils.encrypt(this.captchaV.uuid()))
.mobile(StringConstants.EMPTY)
.build();
private UserV getUserVByAuthorizationCodeAuth() {
try {
String username = getParameterValue(Constants.USERNAME);
String password = getParameterValue(Constants.PASSWORD);
String tenantCode = getParameterValue(Constants.TENANT_CODE);
return UserV.builder()
.username(AESUtils.encrypt(username))
.password(password)
.tenantCode(tenantCode)
.mail(StringConstants.EMPTY)
.mobile(StringConstants.EMPTY)
.build();
}
catch (Exception ex) {
log.error("getUserVByAuthorizationCodeAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
}
}

private UserV getUserVByMobileAuth() {
try {
return UserV.builder()
.username(StringConstants.EMPTY)
.tenantCode(getParameterValue(Constants.TENANT_CODE))
.mail(StringConstants.EMPTY)
.mobile(AESUtils.encrypt(this.captchaV.uuid()))
.build();
}
catch (Exception ex) {
log.error("getUserVByMobileAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex);
}
}

private UserV getUserVByMailAuth() {
try {
return UserV.builder()
.username(StringConstants.EMPTY)
.tenantCode(getParameterValue(Constants.TENANT_CODE))
.mail(AESUtils.encrypt(this.captchaV.uuid()))
.mobile(StringConstants.EMPTY)
.build();
}
catch (Exception ex) {
log.error("getUserVByMailAuth error: {}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. Globalexception masked as iae 🐞 Bug ✓ Correctness

AuthA now catches exceptions from RSA/AES operations and rethrows IllegalArgumentException, which
converts GlobalException/SystemException into a non-GlobalException and bypasses OAuth2 error
translation. As a result, malformed/invalid encrypted credentials can surface as generic
RuntimeException/500 instead of a structured OAuth2/GlobalException response.
Agent Prompt
## Issue description
`AuthA` converts `GlobalException`/`SystemException` (e.g., from `RSAUtils.decryptByPrivateKey`) into `IllegalArgumentException`. This breaks the downstream exception translation that relies on `GlobalException` and can turn normal auth failures into generic 500s.

## Issue Context
- `RSAUtils.decryptByPrivateKey(...)` throws `SystemException` (a `GlobalException`) on decrypt failure.
- `AbstractOAuth2AuthenticationProvider.authenticate(...)` only converts `GlobalException` into an `OAuth2AuthenticationException`; other exceptions are wrapped into a `RuntimeException`.

## Fix Focus Areas
- Ensure `GlobalException` is rethrown unchanged (do not wrap).
- For non-Global exceptions, wrap into a `SystemException`/`BizException` with an appropriate code/message and preserve the cause (e.g., `new SystemException(code, msg, ex)`), rather than `IllegalArgumentException(ex.getMessage())`.
- Keep the original exception as the cause to preserve stack traces.

### Focus lines
- laokou-service/laokou-auth/laokou-auth-domain/src/main/java/org/laokou/auth/model/AuthA.java[435-504]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +106 to 140
public static LoginEvent toDomainEvent(HttpServletRequest request, AuthA authA, GlobalException gex) {
try {
Capabilities capabilities = RequestUtils.getCapabilities(request);
String ip = IpUtils.getIpAddr(request);
int status = LoginStatus.OK.getCode();
UserE userE = authA.getUserE();
Optional<UserE> optional = Optional.ofNullable(userE);
Long creator = optional.map(UserE::getId).orElse(null);
Long tenantId = optional.map(UserE::getTenantId).orElse(null);
Long deptId = optional.map(UserE::getDeptId).orElse(null);
String errorMessage = StringConstants.EMPTY;
if (ObjectUtils.isNotNull(gex)) {
status = LoginStatus.FAIL.getCode();
errorMessage = gex.getMsg();
}
return LoginEvent.builder()
.id(authA.getId())
.username(authA.getLoginName())
.ip(ip)
.address(AddressUtils.getRealAddress(ip))
.browser(capabilities.getBrowser())
.os(capabilities.getPlatform())
.status(status)
.errorMessage(errorMessage)
.type(authA.getGrantType().getCode())
.loginTime(authA.getCreateTime())
.tenantId(tenantId)
.creator(creator)
.deptId(deptId)
.build();
}
catch (InetAddressException | IOException | InterruptedException ex) {
log.error("错误信息:{}", ex.getMessage(), ex);
throw new IllegalArgumentException(ex.getMessage());
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. Login depends on ip lookup 🐞 Bug ⛯ Reliability

LoginLogConvertor.toDomainEvent now rethrows IllegalArgumentException on address/IP lookup failures
(including InterruptedException), and OAuth2AuthenticationProcessor calls it on the success path
before returning the authentication token. A transient geo/IP lookup failure can therefore abort an
otherwise successful login and the InterruptedException handling clears the interrupt flag.
Agent Prompt
## Issue description
`LoginLogConvertor.toDomainEvent(...)` throws `IllegalArgumentException` when IP->address resolution fails, and it catches `InterruptedException` without restoring interrupt status. Because the auth processor calls `toDomainEvent` on the success path, a transient lookup failure can break successful authentication.

## Issue Context
- `OAuth2AuthenticationProcessor.authentication(...)` calls `LoginLogConvertor.toDomainEvent(request, authA, null)` before returning the token.
- `AddressUtils.getRealAddress(...)` declares `throws InetAddressException, IOException, InterruptedException`.

## Fix Focus Areas
- Do not throw from `toDomainEvent` for address/capabilities lookup failures; instead:
  - Log the failure
  - Use safe defaults (e.g., empty/"unknown" address/browser/os)
  - Still return a `LoginEvent`
- If `InterruptedException` is caught, call `Thread.currentThread().interrupt()` before continuing/returning.
- Preserve causes if you must rethrow, and prefer a domain-specific `GlobalException` rather than `IllegalArgumentException`.

### Focus lines
- laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/convertor/LoginLogConvertor.java[106-140]
- laokou-service/laokou-auth/laokou-auth-infrastructure/src/main/java/org/laokou/auth/config/authentication/OAuth2AuthenticationProcessor.java[48-69]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

@codecov
Copy link

codecov bot commented Mar 20, 2026

Codecov Report

❌ Patch coverage is 73.33333% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.27%. Comparing base (559cc4a) to head (cc742e0).
⚠️ Report is 19 commits behind head on master.

Files with missing lines Patch % Lines
...ain/src/main/java/org/laokou/auth/model/AuthA.java 73.33% 12 Missing ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##             master    #5910      +/-   ##
============================================
- Coverage     58.29%   58.27%   -0.03%     
- Complexity     1145     1147       +2     
============================================
  Files           270      270              
  Lines          5364     5385      +21     
  Branches        339      339              
============================================
+ Hits           3127     3138      +11     
- Misses         2061     2071      +10     
  Partials        176      176              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant