OAuth2Config: IllegalStateException: 对于 MAC 签名,您无需单独指定验证程序密钥



我正在尝试创建一个使用带有 JWT 令牌的 Spring Security 的项目。但是,当我部署它时,我在SecurityConfigtokenEnhancer()方法上收到以下错误:

org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'tokenEnhancer' defined 
in testproject.security.OAuth2Config: 
Invocation of init method failed; nested exception is 
java.lang.IllegalStateException: For MAC signing you 
do not need to specify the verifier key separately, 
and if you do it must match the signing key
at org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796)
at org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:595)
at org.springframework.beans.factory.support.
AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:517)
at org.springframework.beans.factory.support.
AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:323)

我不知道如何解决它。

安全配置.java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter  {
private UserDetailsService userDetailsService;
@Autowired
private JwtRequestFilter jwtRequestFilter;
public SecurityConfig(
UserDetailsServiceImpl userDetailsService)  {
this.userDetailsService = userDetailsService;
}
@Bean
DaoAuthenticationProvider authenticationProvider(){
DaoAuthenticationProvider daoAuthenticationProvider =
new DaoAuthenticationProvider();
daoAuthenticationProvider.setPasswordEncoder(passwordEncoder());
daoAuthenticationProvider.setUserDetailsService(this.userDetailsService);
return daoAuthenticationProvider;
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder());
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/authenticate")
.permitAll().
anyRequest().authenticated().and().
exceptionHandling()
.and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
httpSecurity.addFilterBefore(jwtRequestFilter,
UsernamePasswordAuthenticationFilter.class);
}

@Bean
PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}

OAuth2Config.java

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
private String clientid = "tutorialspoint";
private String clientSecret = "my-secret-key";
private String privateKey = "private key";
private String publicKey = "public key";
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public JwtAccessTokenConverter tokenEnhancer() {
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
converter.setSigningKey(privateKey);
converter.setVerifierKey(publicKey);
return converter;
}
@Bean
public JwtTokenStore tokenStore() {
return new JwtTokenStore(tokenEnhancer());
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())
.accessTokenConverter(tokenEnhancer());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient(clientid)
.secret(clientSecret).scopes("read", "write")
.authorizedGrantTypes("password", "refresh_token")
.accessTokenValiditySeconds(20000)
.refreshTokenValiditySeconds(20000);
}
}

JwtRequestFilter.java

@Component
public class JwtRequestFilter extends OncePerRequestFilter {
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
private JwtUtil jwtUtil;
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response, FilterChain chain)
throws ServletException, IOException {
final String authorizationHeader = request.getHeader("Authorization");
String username = null;
String jwt = null;
if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) {
jwt = authorizationHeader.substring(7);
username = jwtUtil.extractUsername(jwt);
}
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
if (jwtUtil.validateToken(jwt, userDetails)) {
UsernamePasswordAuthenticationToken
usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
userDetails, null, userDetails.getAuthorities());
usernamePasswordAuthenticationToken
.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
}
}
chain.doFilter(request, response);
}
}

编辑

我尝试将privateKey值和publicKey值更改为在线生成:

private String privateKey = "-----BEGIN RSA PRIVATE KEY-----n" +
"Proc-Type: 4,ENCRYPTEDn" +
"DEK-Info: DES-EDE3-CBC,A033B6E4DCA5218Fn" +
"n" +
"QyTlIaijNU0EQi+DZKcihKNEDREpkG+14bKsrRh2NudDM42K37h6hQWNn859DYLTn" +
"J2mdF4ghs2PGZqxRukrsrfIA1VVFoTObGlLQCFXb1L+kH90vDEbB1qdxexedRJZFn" +
"NqQ9GXaGmUieGhBnMroSPshKvwmMzPXFcH/eYv/4RIKo9ejeWkx54NZtM1Boy2SEn" +
"lHGlZpVxEupKZ9fpw6bcr/TsA0cIuUHRtvf8lwgmBgKBXU9F8c2PhhVgalE2RcJvn" +
"q9ujFvF6FU9AtEZsV9+wJznoRrQlY447bnh9qlfI3JyGoz6czX9foeB70CWJM4TFn" +
"SZigb7TxhhBVtiIRsA5ILwXuSDQ0TDA08oG9WP5dQ0oplUkGa6AcEQnO4I9y4E3wn" +
"3UL314kndgxrgUF+IMDedfMxWHslFNGmz2VVibKtnOZEyjHZG1YqpUOqKP8WdJWSn" +
"OzOxkbydUtFoNPJ5V2rd/PNpI0t7sxTa2LUGpvHJXvSXTqQufp3ascnRTOpAQC2Hn" +
"mjpRGx1SRIJA09WAfpIgGP5Ap6/cZIyZrgAlIQnGpDdOG9A5WRLPb6H2jUiDJnEvn" +
"ItNfDNj5fOQiL0tyBW5ulMBBNlRJxyP65XhU7H/6kn3AuW7Qg/znZTAIQnAr9rIYn" +
"eb4HUsF176ApezxeKLU+Z4fFNhxUFRB19/CHDjrKoaJxBoVwbH7bFOUP35BLPX5rn" +
"gSIlT6UJB/WEiewyhSNaYdvx0YLl7shsoLK/+62n0xoKd0zibDsWzTaNK5p06Mvtn" +
"JyHf86/iotOlvMZ/I+LQ7/yL4U1Z3AouZ9srG/VMeEXeHajfyg4Y9L8MTEESnQBVn" +
"N1IVCEHcUCg3EthAYWL/3OqcOwbNNfcUmLVH5INuAWyErPjKybCp6iW3ArAoPlUNn" +
"qAAqCDRI1V7qCV9nBNHMQlC8m7BuLwoD7kbNTHPOcuhM76ow+Y2jvrhJrkq/pblin" +
"TwE5kDpOc6xIGVRmuxy2yYXmvppYv//GiepT89J0wCWacODVZF75yWO83556rGynn" +
"rnqyMkDpZDqwRG3ktgWZNKDjAbbpcWmyFHobws/ZMKsXQiIuoU03smC3mCw1VMKan" +
"YaRf6mEaa1pzNMqmQlD0aHWYN/9zeeMQHSTb7G2VeSB+yLmBvDeq6kyVoElx8Arkn" +
"2/lniftEhO85AAJz5hIEHSqi1MRzyxtb0qPjAB+NzFw2pgifVsEhqBPdvVhI1piZn" +
"/nedPy808+GC/PF1BOR6S4ZdPFOUkRf4OLD3AbXTJsgYn1LAV2mC2lsUrnrWjhhTn" +
"jc41TmSue4FMf+s1ADntA+e9JB/uyePh5qrsLBqU6mjiIRf99nZ5qSqlgj6HuxWHn" +
"dGvgcZlTS1U5wsWSBDhrWXV703hQs3RSBCJshD44g5+iVneFLRO7fVeX+acK5A8kn" +
"+dc5ihVSsKI7wcchdrrta7MYdDNfd+6NlnCeKKhV9Mh9TheaxlVzmmKcUgMeLlqNn" +
"aGpojVX07F2HnoRah2Kq3h6C23g1RjO5zLVjJ5ZP5QcUKHqIHkv9Yxiy/IB0PPLpn" +
"jvMdn13O+KTiNQut/2IiOWpOIa0BgWVPbEZz5AUFIovztyFZOYDTPAidDGE8wxGKn" +
"-----END RSA PRIVATE KEY-----";
private String publicKey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCRGhJOZwdDh86Gaai3LLQfMTtNhvKjPElGeFXG/2FgWWRXRRZppAVLL8muWhzayt5mTl9a6eIhtH8qo1bJAdB+0fXErj4bx5ABaoU/O+jCLewLqRo13df+ryz9KLKoyB15JcEORMA6Izqp50mLGlw+vZn/cEc0deTC7GgqxmfzfH9VpbLr2GRB2HTk5oDZOE5uK99L7J5nOuSU7pGIu+RyOEWiXWX65i242wVvjdiBBEGCo1yHGZC7QX+UFHJMCAZzuyPbvnmxsbIkZJyelfQA3zzL8hmP0uEI8KJIqhCPG68FQ09U46G9yZOnOkywEum1sV8extcBtfeiYich1UK5";

但是,现在部署会导致

org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 
'tokenEnhancer' defined in testproject.security.OAuth2Config: 
Bean instantiation via factory method failed;
nested exception is org.springframework.beans.BeanInstantiationException: 
Failed to instantiate [org.springframework.security.oauth2
.provider.token.store.JwtAccessTokenConverter]:
Factory method 'tokenEnhancer' threw exception;
nested exception is org.springframework.security.jwt.codec
.InvalidBase64CharacterException: 
Bad Base64 input character decimal 45 in array position 5
at

错误

任何帮助,不胜感激。

我认为问题是您正在传递SSH公钥。您需要先生成一个密钥对,然后才能导出公钥:

$ keytool -genkeypair -alias mytest -keyalg RSA -keypass changeit -keystore keystore.jks -storepass changeit
$ keytool -list -rfc --keystore keystore.jks | openssl x509 -inform pem -pubkey > pubkey.txt

您可以加载密钥:

KeyPair keyPair = new KeyStoreKeyFactory(
new ClassPathResource("keystore.jks"), "changeit".toCharArray())
.getKeyPair("mytest");

您的授权服务器将使用上述KeyPair进行签名,资源服务器将使用公钥。