我有我的OAUTH2服务器,其他服务需要请求jwt令牌才能访问端点。
到目前为止,一切都很好。
但是现在我正在编写测试,它们都未经授权返回错误401。我已经知道,这是因为测试未向OAuth2服务器发出任何请求。
我想知道的是如何从JWT或oauth2服务器上进行模拟。
答案 0 :(得分:2)
最简单的方法是直接模拟JWT令牌,可以为测试使用其他签名密钥,这样就不会为后端创建安全中断。
答案 1 :(得分:1)
如果您需要模拟JWT,最好的解决方案是使用 Nimbus JWT + JOSE library
使用针对您的测试的JWT生成器例如,下面是直接从JSON Web Token (JWT) with RSA signature提取的代码,它显示了JWT的生成以及与测试非常相似的断言。
import java.util.Date;
import com.nimbusds.jose.*;
import com.nimbusds.jose.crypto.*;
import com.nimbusds.jose.jwk.*;
import com.nimbusds.jose.jwk.gen.*;
import com.nimbusds.jwt.*;
// RSA signatures require a public and private RSA key pair, the public key
// must be made known to the JWS recipient in order to verify the signatures
RSAKey rsaJWK = new RSAKeyGenerator(2048)
.keyID("123")
.generate();
RSAKey rsaPublicJWK = rsaJWK.toPublicJWK();
// Create RSA-signer with the private key
JWSSigner signer = new RSASSASigner(rsaJWK);
// Prepare JWT with claims set
JWTClaimsSet claimsSet = new JWTClaimsSet.Builder()
.subject("alice")
.issuer("https://c2id.com")
.expirationTime(new Date(new Date().getTime() + 60 * 1000))
.build();
SignedJWT signedJWT = new SignedJWT(
new JWSHeader.Builder(JWSAlgorithm.RS256).keyID(rsaJWK.getKeyID()).build(),
claimsSet);
// Compute the RSA signature
signedJWT.sign(signer);
// To serialize to compact form, produces something like
// eyJhbGciOiJSUzI1NiJ9.SW4gUlNBIHdlIHRydXN0IQ.IRMQENi4nJyp4er2L
// mZq3ivwoAjqa1uUkSBKFIX7ATndFF5ivnt-m8uApHO4kfIFOrW7w2Ezmlg3Qd
// maXlS9DhN0nUk_hGI3amEjkKd0BWYCB8vfUbUv0XGjQip78AI4z1PrFRNidm7
// -jPDm5Iq0SZnjKjCNS5Q15fokXZc8u0A
String s = signedJWT.serialize();
// On the consumer side, parse the JWS and verify its RSA signature
signedJWT = SignedJWT.parse(s);
JWSVerifier verifier = new RSASSAVerifier(rsaPublicJWK);
assertTrue(signedJWT.verify(verifier));
// Retrieve / verify the JWT claims according to the app requirements
assertEquals("alice", signedJWT.getJWTClaimsSet().getSubject());
assertEquals("https://c2id.com", signedJWT.getJWTClaimsSet().getIssuer());
assertTrue(new Date().before(signedJWT.getJWTClaimsSet().getExpirationTime()));
我要做的是将类似的JWT生成功能提取到专用类中。为此添加一些构造函数参数(或使用构建器模式),并将其用于所有我的模拟返回。这样,您就可以测试正确,不正确以及意外的情况。
答案 2 :(得分:0)
我尝试了两种技巧,但没有成功。
我的资源服务器配置:
@Configuration
@EnableResourceServer
public class ServidorDeRecursos extends ResourceServerConfigurerAdapter {
@Autowired
private ConfiguracaoDeToken configuracaoDeToken;
@Override
public void configure(final HttpSecurity http) throws Exception {
// @formatter:off
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)
.and()
.authorizeRequests().anyRequest().permitAll();
// @formatter:on
}
@Override
public void configure(final ResourceServerSecurityConfigurer config) {
config.tokenServices(configuracaoDeToken.tokenServices());
}
}
我的令牌配置
@Configuration
public class ConfiguracaoDeToken {
@Autowired
private ConversorDeTokenDeAcessoPersonalizado conversorDeTokenDeAcessoPersonalizado;
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(accessTokenConverter());
}
@Bean
public DefaultTokenServices tokenServices() {
final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
return defaultTokenServices;
}
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setAccessTokenConverter(conversorDeTokenDeAcessoPersonalizado);
final Resource resource = new ClassPathResource("public.txt");
String publicKey = null;
try {
publicKey = IOUtils.toString(resource.getInputStream());
} catch (final IOException e) {
throw new RuntimeException(e);
}
converter.setVerifierKey(publicKey);
return converter;
}
}
@Component
public class ConversorDeTokenDeAcessoPersonalizado extends DefaultAccessTokenConverter {
@Override
public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
OAuth2Authentication authentication = super.extractAuthentication(claims);
authentication.setDetails(claims);
return authentication;
}
}
@Component
public class TokenPayload {
private Map<String, Object> getExtraInfo() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
OAuth2AuthenticationDetails oauthDetails = (OAuth2AuthenticationDetails) auth.getDetails();
@SuppressWarnings("unchecked")
var details = (Map<String, Object>) oauthDetails.getDecodedDetails();
return details;
}
public String payloadLogin() {
return getExtraInfo().get("user_name").toString();
}
public Long payloadIdEmpresa() {
return Long.parseLong(getExtraInfo().get("idEmpresa").toString());
}
public Long payloadIdFuncionario() {
return Long.parseLong(getExtraInfo().get("idFuncionario").toString());
}
}