【问题标题】:Mocking @AuthenticationPrincipal for a unit test模拟 @AuthenticationPrincipal 进行单元测试
【发布时间】:2020-10-26 18:52:00
【问题描述】:

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

【问题讨论】:

  • 能分享一下要测试的方法和要执行的测试吗?模拟什么以及如何模拟?
  • 如果你使用 mockito 你可以做 Authentication authentication = mock(Authentication.class); SecurityContext securityContext = mock(SecurityContext.class); when(securityContext.getAuthentication()).thenReturn(authentication); SecurityContextHolder.setContext(securityContext); when(SecurityContextHolder.getContext().getAuthentication().getPrincipal()) .thenReturn(currentUser()); currentUser() 方法返回用户对象的地方

标签: java spring unit-testing authentication lombok


【解决方案1】:

想到的最简单的解决方案是@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" };
}

  1. 模拟用户类
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;
    }
}

【讨论】:

    猜你喜欢
    • 2018-09-04
    • 2013-11-12
    • 2018-11-21
    • 2018-10-19
    • 2013-07-24
    • 1970-01-01
    • 1970-01-01
    • 2022-10-18
    • 2018-04-04
    相关资源
    最近更新 更多