java - 我如何模拟 JWT.decode?
问题描述
我在我的 Spring Boot 应用程序中使用这个库。
<dependency>
<groupId>com.auth0</groupId>
<artifactId>java-jwt</artifactId>
<version>3.9.0</version>
</dependency>
如何进行单元测试DecodedJWT jwt = JWT.decode(accessToken);
?
我可以传入一个实际的令牌,但这不是正确的方法。
我的 Spring Boot 应用程序中有这个 JwtAuthenticationFilter。
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
@Value("${clientid}")
private String clientid;
@Autowired
private AuthenticationService authenticationService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException, InvalidRoleException {
getJwtFromRequest(request, response, filterChain);
}
private void getJwtFromRequest(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String bearerToken = request.getHeader("Authorization");
if (!StringUtils.hasText(bearerToken) || !bearerToken.startsWith("Bearer ")) {
throw new AccessTokenMissingException("No access token found in request headers.");
}
try {
String accessToken = bearerToken.substring(7);
// this will also throw error when unable to reach auth server
ResponseEntity<String> result = authenticationService.getUserInfo(accessToken);
// Invalid access token
if (!result.getStatusCode().is2xxSuccessful()) {
throw new InvalidAccessTokenException("Invalid access token.");
}
DecodedJWT jwt = JWT.decode(accessToken);
String username = jwt.getClaim("preferred_username").asString();
Map<String, Object> resources = jwt.getClaim("resource_access").asMap();
Object roles = ((Map<String, Object>) resources.get(clientid)).get("roles");
List<String> rolesList = (ArrayList<String>)roles;
UserInfo user = new UserInfo();
user.setUsername(username);
user.setRole(rolesList);
// Step 3: Set username to security context
UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
user.getUsername(), null, AuthUtil.getAuthRole(user.getRole()));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
} catch (HttpClientErrorException.Unauthorized | JWTDecodeException e) {
throw new InvalidAccessTokenException("Invalid access token.");
}
filterChain.doFilter(request, response);
}
}
解决方案
您可以使用不同的策略/选项,所有这些都将起作用:
根本不要模拟 JWT.decode,将其视为应在测试中运行的实用方法。它背后的直觉是,如果您的课程使用
Math.max(a,b)
代码或某些日期时间操作DateTime.of(...)
,您会在测试中模拟它吗?可能不会......尽管在这种情况下,您可能必须在测试中使用真正可解码的令牌使用 PowerMockito 模拟静态调用(我真的不推荐这种方式,但如果您不想更改代码,它会完成这项工作)。
进行重构,将解码功能提取到接口并将其用作过滤器中的依赖项:
public interface JWTDecoder {
DecodedJWT decode(String token); // I assume its string for simplicity
}
@Component
public class StdJWTDecoder implements JWTDecoder {
public DecodedJWT decode(String token) {
return JWT.decode(tokent);
}
public class JwtAuthenticationFilter ... {
private final JWTDecoder jwtDecoder;
public JwtAuthenticationFilter(JWTDecoder jwtDecoder) {
this.jwtDecoder = jwtDecoder;
}
....
private void getJwtFromRequest(HttpServletRequest request, HttpServletResponse
response, FilterChain filterChain) {
...
// instead of:
DecodedJWT jwt = JWT.decode(accessToken);
// use this:
DecodedJWT jwt = jwtDecoder.decode(accessToken);
...
}
}
JwtDecoder
使用这种方法,您可以轻松地用 mockito模拟
推荐阅读
- javascript - JavaScript:为 jquery ajax 重试添加延迟
- ruby-on-rails - Ruby 默认参数:静态还是动态?
- c# - 使用托管服务帐户将文件从 IIS 写入网络驱动器
- c# - 使用具有不同层的 LINQ 意味着我无法访问特定类型
- python - aws lambda 逐行读取并写入文件
- c++ - 使用 C++ 在 Active Directory GPO 中管理“安全设置”
- flutter - GridView中的颤振图像滚动滞后
- python - 如何指定来自 rest_framework.test.Client 的 Accept 标头?
- c++ - 对于 C++,是否可以打印派生类对象的超类成员
- class - Kotlin 中的这些类有什么区别?