嗨,我正在尝试实现一个Spring Boot Resource Server,它可以从我的身份验证服务器检查令牌。
我遇到的问题是我在令牌验证中不断遇到错误
{"error":"invalid_token","error_description":"e9d5029d-8f2a-4001-98dd-d6d6afb4f8c3"}
我正在与资源服务器在同一台计算机上运行身份验证服务器。测试时,请执行以下步骤:
1)通过以下方式请求令牌:curl -X POST http://localhost:9999/oauth/token --header "Authorization:Basic YXBwY2xpZW50OmFwcGNsaWVudEAxMjM=" -d "grant_type=password" -d "username=john" -d "password=john@123"
2)然后,我可以验证令牌curl -X POST http://localhost:9999/oauth/check_token -d "token=e9d5029d-8f2a-4001-98dd-d6d6afb4f8c3"
3)然后,我尝试将请求发送到资源服务器以访问页面,
curl -X GET http://localhost:8010/favouritePet --header "Authorization:Bearer e9d5029d-8f2a-4001-98dd-d6d6afb4f8c3"
返回{"error":"invalid_token","error_description":"e9d5029d-8f2a-4001-98dd-d6d6afb4f8c3"}
我希望有人可以看到问题所在:)
资源服务器上的调试控制台
2019-12-18 20:09:51.722 INFO 7436 --- [nio-8010-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-12-18 20:09:51.722 INFO 7436 --- [nio-8010-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-12-18 20:09:51.722 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.servlet.DispatcherServlet : Detected StandardServletMultipartResolver
2019-12-18 20:09:51.730 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.servlet.DispatcherServlet : enableLoggingRequestDetails='true': request parameters and headers will be shown which may lead to unsafe logging of potentially sensitive data
2019-12-18 20:09:51.730 INFO 7436 --- [nio-8010-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 8 ms
2019-12-18 20:09:51.772 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.client.RestTemplate : HTTP POST http://localhost:9999/oauth/check_token
2019-12-18 20:09:51.784 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.client.RestTemplate : Accept=[application/json, application/*+json]
2019-12-18 20:09:51.786 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.client.RestTemplate : Writing [{token=[e9d5029d-8f2a-4001-98dd-d6d6afb4f8c3]}] as "application/x-www-form-urlencoded"
2019-12-18 20:09:51.837 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.client.RestTemplate : Response 200 OK
2019-12-18 20:09:51.838 DEBUG 7436 --- [nio-8010-exec-1] o.s.web.client.RestTemplate : Reading to [java.util.Map<?, ?>]
身份验证服务器上的调试控制台
2019-12-18 20:09:51.825 DEBUG 22232 --- [nio-9999-exec-3] o.s.web.servlet.DispatcherServlet : POST "/oauth/check_token", parameters={masked}
2019-12-18 20:09:51.835 DEBUG 22232 --- [nio-9999-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Using 'application/json', given [application/json, application/*+json] and supported [application/json, application/*+json, application/json, application/*+json]
2019-12-18 20:09:51.835 DEBUG 22232 --- [nio-9999-exec-3] m.m.a.RequestResponseBodyMethodProcessor : Writing [{aud=[petstore], exp=1576698083, user_name=john, authorities=[AUTHORIZED_PETSTORE_ADMIN, AUTHORIZED_ (truncated)...]
2019-12-18 20:09:51.836 DEBUG 22232 --- [nio-9999-exec-3] o.s.web.servlet.DispatcherServlet : Completed 200 OK
身份验证服务器
package habuma;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
public class JpaConfig {
@Bean
public DataSource getDataSource()
{
DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create();
dataSourceBuilder.url("jdbc:mysql://192.168.1.38:3306/auth?useLegacyDatetimeCode=false&serverTimezone=UTC");
dataSourceBuilder.username("xxxxxx");
dataSourceBuilder.password("xxxxxxxxx");
dataSourceBuilder.driverClassName(com.mysql.cj.jdbc.Driver.class.getName());
return dataSourceBuilder.build();
}
}
package habuma;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
import javax.sql.DataSource;
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Autowired
DataSource dataSource;
@Qualifier("org.springframework.security.userDetailsService")
@Autowired
private UserDetailsService usrSvc;
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
security.checkTokenAccess("isAuthenticated()");
security.checkTokenAccess("permitAll");
security.passwordEncoder(clientPasswordEncoder());
}
// Configure the token store and authentication manager
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//@formatter:off
endpoints.tokenStore(tokenStore()).authenticationManager(authenticationManager).userDetailsService(usrSvc);
//@formatter:on
}
// Configure a client store. In-memory for simplicity, but consider other
// options for real apps.
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
//@formatter:off
clients.jdbc(dataSource);
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean("clientPasswordEncoder")
PasswordEncoder clientPasswordEncoder() {
return new BCryptPasswordEncoder(8);
}
}
package habuma;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class OAuthAuthServerApplication {
public static void main(String[] args) {
SpringApplication.run(OAuthAuthServerApplication.class, args);
}
}
package habuma;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.security.Principal;
@RestController
@RequestMapping("/principal")
public class rest {
@GetMapping
public Principal retrievePrincipal(Principal principal) {
return principal;
}
}
package habuma;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.BeanIds;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configurers.provisioning.JdbcUserDetailsManagerConfigurer;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
DataSource dataSource;
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
JdbcUserDetailsManagerConfigurer<AuthenticationManagerBuilder> cfg = auth.jdbcAuthentication()
.passwordEncoder(userPasswordEncoder()).dataSource(dataSource);
cfg.getUserDetailsService().setEnableGroups(true);
cfg.getUserDetailsService().setEnableAuthorities(false);
}
@Override
@Bean(BeanIds.USER_DETAILS_SERVICE)
public UserDetailsService userDetailsServiceBean() throws Exception {
return super.userDetailsServiceBean();
}
@Bean("userPasswordEncoder")
PasswordEncoder userPasswordEncoder() {
return new BCryptPasswordEncoder(4);
}
}
资源服务器
package com.Cleverparking.Resource.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
@EnableResourceServer
@SpringBootApplication
public class ResourceServerApplication {
public static void main(String[] args) {
SpringApplication.run(ResourceServerApplication.class, args);
}
}
package com.Cleverparking.Resource.server;
import org.springframework.boot.actuate.trace.http.HttpTrace;
import org.springframework.http.HttpStatus;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class RestControllerURI {
@GetMapping("pet")
@PreAuthorize("hasAuthority('AUTHORIZED_PETSTORE_USER')")
public String pet(HttpTrace.Principal principal) {
return "Hi " + principal.getName() + ". My pet is dog";
}
@GetMapping("hello")
public String hello(HttpStatus status){
return status.toString();
}
@GetMapping("favouritePet")
@PreAuthorize("hasAuthority('AUTHORIZED_PETSTORE_ADMIN')")
public String favouritePet(HttpTrace.Principal principal) {
return "Hi " + principal.getName() + ". My favourite pet is cat";
}
}
package com.Cleverparking.Resource.server;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
//@Order(SecurityProperties.BASIC_AUTH_ORDER)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
server.port=8010
security.oauth2.client.client-id=appclient
security.oauth2.client.client-secret=appclient@123
security.oauth2.resource.id=petstore
security.oauth2.resource.token-info-uri=http://localhost:9999/oauth/check_token
logging.level.org.springframework.web= DEBUG
logging.level.org.hibernate= DEBUG
spring.http.log-request-details=true