java - 模拟@AuthenticationPrincipal进行单元测试

标签 java spring unit-testing authentication lombok

我是 spring 和 lombok 的新手。我正在对 Controller 进行单元测试,其中该方法使用 @AuthenticationPrincipal。根据我的阅读,它将经过身份验证的用户的信息传递到方法中。有没有办法在单元测试中模拟这个?

最佳答案

想到的最简单的解决方案是@WithMockUser。它满足您的要求。但是,如果您对此不满意,您可以创建注释并根据您的需要进行调整。

我假设您已经尝试过@WithMockUser,但它确实不符合您的需求。

有三项重要任务。第一个是创建注释,然后创建一个代表系统用户的类,最后创建SecurityContextFactory

  1. 让我们从注释开始
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

import org.springframework.security.test.context.support.WithSecurityContext;

@Retention(RetentionPolicy.RUNTIME)
@WithSecurityContext(factory = WithMockAaronSecurityContextFactory.class)
public @interface WithAaronUser {
    String username() default "TestUser";
    String[] roles() default { "ROLE_ADMIN" };
}

  • 模拟用户类
  • import java.util.Collection;
    import java.util.stream.Collectors;
    import java.util.stream.Stream;
    
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.SimpleGrantedAuthority;
    
    public class MockUserDetails {
    
        private String username;
        private Collection<? extends GrantedAuthority> authorities;
        
        public MockUserDetails(String username, String[] roles) {
            this.username = username;
            this.authorities = Stream.of(roles)
                    .map(role -> new SimpleGrantedAuthority(role)).collect(Collectors.toSet());
        }
    
        public String getUsername() {
            return username;
        }
    
        public Collection<? extends GrantedAuthority> getAuthorities() {
            return authorities;
        }
    }
    

    3 最后是SecurityContextFactory。请注意,该实现使用与 @WithMockUser 使用相同的工厂类 (WithSecurityContextFactory)。

    import java.io.Serializable;
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    import java.util.Set;
    
    import org.springframework.mock.web.MockHttpServletRequest;
    import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
    import org.springframework.security.core.GrantedAuthority;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.context.SecurityContext;
    import org.springframework.security.core.context.SecurityContextHolder;
    import org.springframework.security.oauth2.provider.OAuth2Authentication;
    import org.springframework.security.oauth2.provider.OAuth2Request;
    import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
    import org.springframework.security.test.context.support.WithSecurityContextFactory;
    
    public class WithMockAaronSecurityContextFactory implements WithSecurityContextFactory<WithAaronUser> {
    
        @Override
        public SecurityContext createSecurityContext(WithAaronUser user) {
    
            MockUserDetails principal = new MockUserDetails(user.username(), user.roles());
    
            MockHttpServletRequest request = new MockHttpServletRequest();
            request.setServerName("www.example.com");
            request.setRequestURI("/token");
            request.setQueryString("param1=value1&param");
            request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, "mocked_token");
            OAuth2AuthenticationDetails authDetails = new OAuth2AuthenticationDetails(request);
            
            Map<String, String> decodedDetails = new HashMap<>();
            decodedDetails.put("first_name", "Jean-Claude");
            decodedDetails.put("last_name", "Van Damme");
            authDetails.setDecodedDetails(decodedDetails);
            
            
            UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(principal.getUsername(), "password", principal.getAuthorities());
            auth.setDetails(authDetails);
            
            
            List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_ADMIN");
            OAuth2Request oAuth2Request = new OAuth2Request(Collections.emptyMap(), "", authorities, true, Collections.emptySet(), Collections.emptySet(), "http://somethig.com", Collections.emptySet(), Collections.emptyMap());
                        
                        
            OAuth2Authentication oAuth = new OAuth2Authentication(getOauth2Request(), auth);
            oAuth.setDetails(authDetails);
                
            SecurityContext context = SecurityContextHolder.createEmptyContext();
            context.setAuthentication(oAuth);
            return context;
        }
    }
    

    关于java - 模拟@AuthenticationPrincipal进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64543266/

    相关文章:

    java - 使用 ListModel 作为模型类型从 JList 中删除项目

    java - 为什么 Pattern.matches ("[a*mn]","aaaa") 不返回 true?获得所需输出的正确代码应该是什么?

    spring - 添加@Autowire时为"No Session found for current thread"

    c++ - 如何在 C++ 的谷歌测试中匹配双 vector 的元素?

    python - 如何运行python测试文件

    Scala Mock Syntax (class _).expects 含义?

    java - Android操作栏自定义颜色样式

    java - 在java中实例化自界泛型

    spring - 具有构造器的Spring Groovy DSL匿名内部bean

    java - Spring session ,部署后从 "local class incompatible"恢复