java - 模拟 @AuthenticationPrincipal 进行单元测试
问题描述
我是春天和龙目岛的新手。我正在为该方法使用@AuthenticationPrincipal 的控制器进行单元测试。根据我的阅读,它将经过身份验证的用户的信息传递给该方法。有没有办法为单元测试模拟这个?
解决方案
想到的最简单的解决方案是@WithMockUser
. 它可以满足您的要求。但是,如果您对它不满意,您可以创建一个注释并根据您的需要进行调整。
我假设您已经尝试过@WithMockUser
,但它确实不符合您的需求。
有三项重要任务。首先是创建一个注解,然后创建一个代表系统用户的类,最后创建SecurityContextFactory。
- 让我们从注释开始
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。请注意,实现使用与使用相同的工厂类 ( WithSecurityContextFactory
) @WithMockUser
。
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¶m");
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;
}
}
推荐阅读
- marklogic - 使用 MarkLogic Java API 进行 CRUD 操作时,无法在 qconsole 中看到 xquery 结果
- object - 筛选符合条件的对象的最佳数据结构
- glsl - 什么是不同的lowp float vT
- python - 非网络、非文件应用程序中的异步性能
- c++ - 无法理解 C++ 指针语法
- reactjs - 我可以在客户端使用 Axios 或 Fetch 调用 Twitter API 吗?
- c# - 从多继承类中调用所有“基”类的更新、启动等的有效方法?
- android - 当游戏是 64 位时,Google Play 控制台 64 位错误
- oracle - 通过引用共享(对象类型)实例
- xamarin.forms - Xamarin.Plugin.Calender 禁用日期