在单元测试中模拟 @AuthenticationPrincipal。

huangapple go评论143阅读模式
英文:

Mocking @AuthenticationPrincipal for a unit test

问题

我是新手对于 Spring 和 Lombok。我正在为一个控制器编写单元测试,该方法使用 @AuthenticationPrincipal。根据我所了解,它会将经过身份验证的用户信息传递给该方法。是否有方法可以在单元测试中模拟这个?

英文:

I am new to spring and lombok. I am working on a unit test for a controller where the method uses @AuthenticationPrincipal. From what I have read it passes the information of the authenticated user into the method. Is there a way to mock this for the unit test?

答案1

得分: 5

以下是您提供的内容的翻译:

最容易想到的解决方案是 @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;
	}
}
  1. 最后是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;
	}
}
英文:

The easiest solution that comes to mind is @WithMockUser. It does what you asked for. But, in case you are not satisfied with it, you can create an annotation and tune it to your needs.

I am assuming that you have tried @WithMockUser and it really didn't fit your needs.

There are three important tasks. The first is creating an annotation followed by creating a class that represents a user of your system and finally creating SecurityContextFactory.

  1. Let's start with the annotation
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 &quot;TestUser&quot;;
String[] roles() default { &quot;ROLE_ADMIN&quot; };
}
  1. A mock user class
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&lt;? extends GrantedAuthority&gt; authorities;
public MockUserDetails(String username, String[] roles) {
this.username = username;
this.authorities = Stream.of(roles)
.map(role -&gt; new SimpleGrantedAuthority(role)).collect(Collectors.toSet());
}
public String getUsername() {
return username;
}
public Collection&lt;? extends GrantedAuthority&gt; getAuthorities() {
return authorities;
}
}

3 Finally the SecurityContextFactory. Note that the implementation uses the same factory class (WithSecurityContextFactory) that @WithMockUser uses.

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&lt;WithAaronUser&gt; {
@Override
public SecurityContext createSecurityContext(WithAaronUser user) {
MockUserDetails principal = new MockUserDetails(user.username(), user.roles());
MockHttpServletRequest request = new MockHttpServletRequest();
request.setServerName(&quot;www.example.com&quot;);
request.setRequestURI(&quot;/token&quot;);
request.setQueryString(&quot;param1=value1&amp;param&quot;);
request.setAttribute(OAuth2AuthenticationDetails.ACCESS_TOKEN_VALUE, &quot;mocked_token&quot;);
OAuth2AuthenticationDetails authDetails = new OAuth2AuthenticationDetails(request);
Map&lt;String, String&gt; decodedDetails = new HashMap&lt;&gt;();
decodedDetails.put(&quot;first_name&quot;, &quot;Jean-Claude&quot;);
decodedDetails.put(&quot;last_name&quot;, &quot;Van Damme&quot;);
authDetails.setDecodedDetails(decodedDetails);
UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken(principal.getUsername(), &quot;password&quot;, principal.getAuthorities());
auth.setDetails(authDetails);
List&lt;GrantedAuthority&gt; authorities = AuthorityUtils.createAuthorityList(&quot;ROLE_ADMIN&quot;);
OAuth2Request oAuth2Request = new OAuth2Request(Collections.emptyMap(), &quot;&quot;, authorities, true, Collections.emptySet(), Collections.emptySet(), &quot;http://somethig.com&quot;, Collections.emptySet(), Collections.emptyMap());
OAuth2Authentication oAuth = new OAuth2Authentication(getOauth2Request(), auth);
oAuth.setDetails(authDetails);
SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(oAuth);
return context;
}
}

huangapple
  • 本文由 发表于 2020年10月27日 02:52:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/64543266.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定