You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

自定义@WithMockCustomUser创建SecurityContext失败问题求助

问题描述

尝试自定义SecurityContext,通过@WithMockCustomUser注解测试评论发布功能(需获取用户邮箱做身份验证),参考Spring Security 4.2.x文档实现后,报错:Unable to create SecurityContext using @springboot.web.CommentsApiControllerTest$WithMockCustomUser,错误堆栈核心为ClassCastException: com.sun.proxy.$Proxy8 cannot be cast to org.springframework.security.test.context.support.WithUserDetails

错误原因

核心问题是类型不匹配:

  • 自定义的@WithMockCustomUser注解指定的WithUserDetailsSecurityContextFactory是为Spring自带的@WithUserDetails注解设计的,泛型绑定为WithSecurityContextFactory<WithUserDetails>
  • 实际传入的是自定义注解对象,导致代理无法转换为WithUserDetails类型,触发类型转换异常

解决方案

为自定义注解实现专属的WithSecurityContextFactory,具体步骤如下:

1. 实现针对@WithMockCustomUser的SecurityContext工厂类

创建专门处理自定义注解的工厂,泛型参数指定为自定义注解类型:

final class WithMockCustomUserSecurityContextFactory implements WithSecurityContextFactory<CommentsApiControllerTest.WithMockCustomUser> {

    @Override
    public SecurityContext createSecurityContext(CommentsApiControllerTest.WithMockCustomUser annotation) {
        // 从自定义注解中提取配置参数
        String name = annotation.name();
        String email = annotation.email();
        Role role = annotation.role();

        // 构建测试用UserDetails对象(需确保你的User类实现了UserDetails接口)
        UserDetails principal = User.builder()
                .name(name)
                .email(email)
                .role(role)
                // 测试场景下密码可设为任意值,无需实际验证
                .password("dummy-password")
                .build();

        // 创建Authentication对象
        Authentication authentication = new UsernamePasswordAuthenticationToken(
                principal,
                principal.getPassword(),
                principal.getAuthorities()
        );

        // 构建并返回SecurityContext
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        context.setAuthentication(authentication);
        return context;
    }
}

2. 更新自定义注解的工厂指向

修改@WithMockCustomUser注解的@WithSecurityContext属性,指向新的工厂类:

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockCustomUserSecurityContextFactory.class, setupBefore = TestExecutionEvent.TEST_EXECUTION)
public @interface WithMockCustomUser {
    String name() default "testName";
    String email() default "testemail@gmail.com";
    Role role() default Role.USER;
}

3. 清理冗余代码

删除原有的WithUserDetailsSecurityContextFactory(若不再使用),同时移除测试类中不需要的UserDetailsService自动注入。

额外说明

  • 如果业务逻辑需要验证数据库中的真实用户,可在工厂类中注入UserRepository,根据注解的邮箱查询用户并构建UserDetails
  • 测试中的@Transactional注解可保留,确保测试数据不会污染数据库

内容的提问来源于stack exchange,提问作者YSEO

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 23:10:54