![](/img/trans.png)
[英]Spring Security and OAuth2 generate token with custom grant type
[英]Spring Security 5 Spring MVC Oauth 2 Password grant type not returning token with /oauth/token
我正在处理一项要求,以允许另一个受信任的应用程序(后端)使用oauth2密码授予连接到我们的API,但我无法使用/ oauth / token获得令牌。 我们的应用程序已经具有运行登录表单的基本表单登录身份验证。
这是原始的WebSecurityConfig,它允许用户使用表单登录。 这已经有一段时间了。
@Configuration
@ComponentScan("config")
@EnableWebSecurity
@Order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
UserDetailsServiceImpl userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and()
.csrf().disable()
.headers().frameOptions().disable()
.and()
.authorizeRequests()
//allow anyone to access the following with the pattern
.antMatchers("/", "/static/**", "/ping", "/topic/**", "/oauth/token" ).permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/").permitAll()
.loginProcessingUrl("/login")
.usernameParameter("username")
.passwordParameter("password")
.and()
.sessionManagement()
.expiredUrl("/")
.and()
.invalidSessionUrl("/");
}
@Bean(name = "corsConfigurationSource")
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedMethods(Arrays.asList("GET", "POST", "OPTIONS", "DELETE", "PUT"));
configuration.setAllowedHeaders(Arrays.asList("Cache-Control", "Authorization", "Content-Type", "content-type", "x-requested-with", "Access-Control-Allow-Origin", "Access-Control-Allow-Headers", "x-auth-token", "x-app-id", "Origin", "Accept", "X-Requested-With", "Access-Control-Request-Method", "Access-Control-Request-Headers"));
configuration.setAllowCredentials(true);
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
auth.authenticationProvider(authProvider());
}
@Bean
public DaoAuthenticationProvider authProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService);
authProvider.setPasswordEncoder(encoder());
return authProvider;
}
@Bean
public PasswordEncoder encoder() {
return new MessageDigestPasswordEncoder("md5");
}
}
这是我添加的新授权服务器设置。 我只是想让最简单的情况运行。 因此,我正在使用内存进行所有操作。
@Configuration
@EnableAuthorizationServer
@ComponentScan ("config")
public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.inMemory().withClient("client")
.secret("clientpassword")
.secret("{noop}secret")
.authorizedGrantTypes("password")
.scopes("read", "write");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore( new InMemoryTokenStore())
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.POST);
}
}
这是我创建的另一个WebSecurityConfig,试图将原来的与新的分开:
@Configuration
@Order(1)
@ComponentScan ("config")
@EnableWebSecurity (debug = true)
public class WebSecurityOauthConfig extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated().and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.csrf().disable();
}
@Autowired
public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.passwordEncoder(NoOpPasswordEncoder.getInstance())
.withUser("user").password("user").roles("ROLE");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
这是版本:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-core</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.3.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-oauth2-client</artifactId>
<version>5.0.7.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-orm</artifactId>
<version>5.0.0.RELEASE</version>
</dependency>
这是我发送的请求:
curl -X POST \
http://localhost:8081/oauth/token \
-H 'Authorization: Basic Y2xpZW50OmNsaWVudHBhc3N3b3Jk' \
-H 'Cache-Control: no-cache' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-H 'Postman-Token: 06a1108e-d620-4e01-b8f7-81eb7a57ae44' \
-H 'content-type: multipart/form-data; boundary=----WebKitFormBoundary7MA4YWxkTrZu0gW' \
-F client_id=client \
-F user=user \
-F password=user \
-F grant_type=password
没有明确的错误。 这是Spring Security的跟踪日志。 从我所看到的,DaoAuthenticationProvider没有正确注册。 我期望使用内存中的用户,但是过滤器链不包括它。 我也尝试过自动连接userDetailsService,但结果是一样的
************************************************************
Request received for POST '/oauth/token':
org.apache.catalina.connector.RequestFacade@47616c04
servletPath:/oauth/token
pathInfo:null
headers:
content-type: multipart/form-data; boundary=--------------------------127172580218970013444831
authorization: Basic Y2xpZW50OmNsaWVudHBhc3N3b3Jk
cache-control: no-cache
postman-token: db0faf20-d49c-485a-8712-4d31bc65615a
user-agent: PostmanRuntime/7.1.5
accept: */*
host: localhost:8081
cookie: JSESSIONID=AC9D0F63FB67F51917751325403CC4B1
accept-encoding: gzip, deflate
content-length: 505
connection: keep-alive
Security filter chain: [
WebAsyncManagerIntegrationFilter
SecurityContextPersistenceFilter
HeaderWriterFilter
LogoutFilter
BasicAuthenticationFilter
RequestCacheAwareFilter
SecurityContextHolderAwareRequestFilter
AnonymousAuthenticationFilter
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
]
************************************************************
2018-09-05 22:42:36 DEBUG OrRequestMatcher:65 - Trying to match using Ant [pattern='/oauth/token']
2018-09-05 22:42:36 DEBUG AntPathRequestMatcher:157 - Checking match of request : '/oauth/token'; against '/oauth/token' 2018-09-05 22:42:36 DEBUG OrRequestMatcher:68 - matched
2018-09-05 22:42:36 DEBUG FilterChainProxy:328 - /oauth/token at position 1 of 11 in additional filter chain; firing Filter: 'WebAsyncManagerIntegrationFilter'
2018-09-05 22:42:36 DEBUG FilterChainProxy:328 - /oauth/token at position 2 of 11 in additional filter chain; firing Filter: 'SecurityContextPersistenceFilter'
2018-09-05 22:42:36 DEBUG FilterChainProxy:328 - /oauth/token at position 3 of 11 in additional filter chain; firing Filter: 'HeaderWriterFilter'
2018-09-05 22:42:36 DEBUG HstsHeaderWriter:130 - Not injecting HSTS header since it did not match the requestMatcher org.springframework.security.web.header.writers.HstsHeaderWriter$SecureRequestMatcher@42b51d34
2018-09-05 22:42:36 DEBUG FilterChainProxy:328 - /oauth/token at position 4 of 11 in additional filter chain; firing Filter: 'LogoutFilter'
2018-09-05 22:42:36 DEBUG OrRequestMatcher:65 - Trying to match using Ant [pattern='/logout', GET]
2018-09-05 22:42:36 DEBUG AntPathRequestMatcher:137 - Request 'POST /oauth/token' doesn't match 'GET /logout
2018-09-05 22:42:36 DEBUG OrRequestMatcher:65 - Trying to match using Ant [pattern='/logout', POST]
2018-09-05 22:42:36 DEBUG AntPathRequestMatcher:157 - Checking match of request : '/oauth/token'; against '/logout'
2018-09-05 22:42:36 DEBUG OrRequestMatcher:65 - Trying to match using Ant [pattern='/logout', PUT]
2018-09-05 22:42:36 DEBUG AntPathRequestMatcher:137 - Request 'POST /oauth/token' doesn't match 'PUT /logout
2018-09-05 22:42:36 DEBUG OrRequestMatcher:65 - Trying to match using Ant [pattern='/logout', DELETE]
2018-09-05 22:42:36 DEBUG AntPathRequestMatcher:137 - Request 'POST /oauth/token' doesn't match 'DELETE /logout
2018-09-05 22:42:36 DEBUG OrRequestMatcher:72 - No matches found
2018-09-05 22:42:36 DEBUG FilterChainProxy:328 - /oauth/token at position 5 of 11 in additional filter chain; firing Filter: 'BasicAuthenticationFilter'
2018-09-05 22:42:36 DEBUG BasicAuthenticationFilter:170 - Basic Authentication Authorization header found for user 'client'
2018-09-05 22:42:36 DEBUG ProviderManager:169 - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2018-09-05 22:42:36 DEBUG DaoAuthenticationProvider:87 - Authentication failed: password does not match stored value
2018-09-05 22:42:36 DEBUG BasicAuthenticationFilter:198 - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
2018-09-05 22:42:36 DEBUG DelegatingAuthenticationEntryPoint:78 - Trying to match using RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]
2018-09-05 22:42:36 DEBUG DelegatingAuthenticationEntryPoint:91 - No match found. Using default entry point org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint@68e001ed
2018-09-05 22:42:36 DEBUG SecurityContextPersistenceFilter:119 - SecurityContextHolder now cleared, as request processing completed
响应为401 Unororized:
<html>
<head>
<title>Apache Tomcat/7.0.47 - Error report</title>
<style>
<!--H1 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:22px;} H2 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:16px;} H3 {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;font-size:14px;} BODY {font-family:Tahoma,Arial,sans-serif;color:black;background-color:white;} B {font-family:Tahoma,Arial,sans-serif;color:white;background-color:#525D76;} P {font-family:Tahoma,Arial,sans-serif;background:white;color:black;font-size:12px;}A {color : black;}A.name {color : black;}HR {color : #525D76;}-->
</style>
</head>
<body>
<h1>HTTP Status 401 - Unauthorized</h1>
<HR size="1" noshade="noshade">
<p>
<b>type</b> Status report
</p>
<p>
<b>message</b>
<u>Unauthorized</u>
</p>
<p>
<b>description</b>
<u>This request requires HTTP authentication.</u>
</p>
<HR size="1" noshade="noshade">
<h3>Apache Tomcat/7.0.47</h3>
</body>
</html>
请帮忙。 任何建议欢迎。
看起来该代码在客户端服务设置中两次调用.secret
:
clients.inMemory().withClient("client")
.secret("clientpassword")
.secret("{noop}secret")
...
并且日志抱怨client
具有错误的凭据:
2018-09-05 22:42:36 DEBUG BasicAuthenticationFilter:170 - Basic Authentication Authorization header found for user 'client'
2018-09-05 22:42:36 DEBUG ProviderManager:169 - Authentication attempt using org.springframework.security.authentication.dao.DaoAuthenticationProvider
2018-09-05 22:42:36 DEBUG DaoAuthenticationProvider:87 - Authentication failed: password does not match stored value
2018-09-05 22:42:36 DEBUG BasicAuthenticationFilter:198 - Authentication request for failed: org.springframework.security.authentication.BadCredentialsException: Bad credentials
如果我从示例请求中对Authorization
标头进行base64解码 ,则您使用的密码是clientpassword
,如果您这样做,它将起作用:
clients.inMemory().withClient("client")
.secret("{noop}clientpassword")
// .secret("{noop}secret")
// omit the other .secret call and continue w/ remaining config
...
另外,当您准备好从探索模式继续进行时,请记住至少将该密码提取到属性文件中并对其进行编码,例如{bcrypt}$2y$12$8UyEwJ1iwyGqXrxfmH...
最后,也许可以通过使用更简单的curl调用(将密码保留为纯文本)来简化某些混淆。 有可能:
curl -v client:clientpassword@localhost:8081/oauth/token -d grant_type=password -d username=user -d password=user
将使一切变得简单并摆在您面前。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.