OAuth2:确认批准不起作用,即使我单击“批准”按钮也拒绝
OAuth2: Confirmation Approval is not working, Denying even when I click Approve button
我已经使用 Spring 集成 Oauth2 创建了一个应用程序。我有自己的自定义登录和授权模板。成功通过身份验证后,它会重定向到 authorize .html ,并在其中请求用户批准。问题是,当我单击“批准”或“拒绝”按钮时,操作总是被拒绝,如下面的table
所示
另外,我们如何使用 oauth2 启用基于 REST 的身份验证和授权。我尝试禁用 csrf 以允许用户进行身份验证和授权,但仍然没有用。
谁能帮我解决这个问题。
您可以从 here 下载并查看完整的应用程序(根据最后建议 19/11/2017 更新)
更新 1
根据@fateddy 的建议,我使用 选项 3 使用 ApprovalStoreUserApprovalHandler。我使用了给定的确切 authorize.html。
假设我的数据库中有两个客户端(client123 和 client789)。
客户端 client123 没有启用自动批准,客户端 client789 为 [=40= 启用了自动批准选项]openid范围。
现在的问题是,当我单击批准按钮时,client123 出现以下异常。
error="invalid_client", error_description="错误的客户端凭据"
OAuth2Config.java如下
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Bean
public UserApprovalHandler userApprovalHandler() {
ApprovalStoreUserApprovalHandler userApprovalHandler= new ApprovalStoreUserApprovalHandler();
userApprovalHandler.setApprovalStore(approvalStore());
userApprovalHandler.setClientDetailsService(clientDetailsService());
userApprovalHandler.setRequestFactory(requestFactory());
return userApprovalHandler;
}
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public DefaultOAuth2RequestFactory requestFactory(){
return new DefaultOAuth2RequestFactory(clientDetailsService());
}
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//endpoints.tokenStore(tokenStore());
// endpoints.approvalStore(approvalStore());
endpoints.userApprovalHandler(userApprovalHandler());
endpoints.authorizationCodeServices(authorizationCodeServices());
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception {
authorizationServerSecurityConfigurer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
authorize.html
<html>
<head>
</head>
<body>
<div class="container">
<h2>Please Confirm</h2>
<p>
Do you authorize "${authorizationRequest.clientId}" at "${authorizationRequest.redirectUri}" to access your protected resources
with scope ${authorizationRequest.scope?join(", ")}.
</p>
<form id="confirmationForm" name="confirmationForm" action="/auth/oauth/authorize" method="post">
<input name="scope.openid" value="true" type="checkbox" /> Read<br>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
</div>
</body>
</html>
参考是提供的project, git-commit 972b85
。
最后你有几个选择。但是让我们看一下当前的项目状态。
授权端点 (/oauth/authorize
) 让用户决定是授权还是拒绝访问(通过显示表单)。然后 UserApprovalHandler
决定是否授权。
现有的 UserAppovalHandler
- 实现需要不同的请求参数才能做出决定 - 这也意味着这会对 /oauth/authorize
- 视图的外观产生影响喜欢。
选项 1
自定义的 /oauth/authorize
-view 包含 <input name="user_oauth_approval" value="true" />
,它需要一个 UserApprovalHandler
来获取所述参数来做出决定。使用 DefaultUserApprovalHandler
(不记得任何决定)将起作用。配置可能如下所示。在这种情况下不需要 Approval-Store。
<form id="confirmationForm" name="confirmationForm"
action="/auth/oauth/authorize" method="post">
<input name="user_oauth_approval" value="true" type="hidden" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
user_oauth_approval=true
请求参数仅在使用 DefaultUserUserApprovalHandler
时才被拾取:
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Bean
UserApprovalHandler userApprovalHandler() {
return new DefaultUserApprovalHandler();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// ...
endpoints.userApprovalHandler(userApprovalHandler());
}
}
选项 2
通过遵循选项 1,但在本例中,通过提供自定义 UserApprovalHandler
来记住任何决定。
选项 3
坚持使用 ApprovalStoreUserApprovalHandler
(在下面使用 TokenStore)需要对形式进行一些调整:
<form id="confirmationForm" name="confirmationForm" action="/auth/oauth/authorize" method="post">
<!--
The ApprovalStoreUserApprovalHandler tests scopes by testing request-params prefixed with `scope.*`
For dynamic input-element rendering one might iterate over
${authorizationRequest.scope}
Provides access to the scope=openid whenever the user checks the checkbox:
-->
<input name="scope.openid" value="true" type="checkbox" /> OpenID<br>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
Auth-Server-Config:
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// ...
// registering an ApprovalStore automaticaly bootstraps `ApprovalStoreUserApprovalHandler`
endpoints.approvalStore(approvalStore());
}
}
选项 N
可能还有其他适合的选项 - 但这取决于您的要求。
我已经使用 Spring 集成 Oauth2 创建了一个应用程序。我有自己的自定义登录和授权模板。成功通过身份验证后,它会重定向到 authorize .html ,并在其中请求用户批准。问题是,当我单击“批准”或“拒绝”按钮时,操作总是被拒绝,如下面的table
所示另外,我们如何使用 oauth2 启用基于 REST 的身份验证和授权。我尝试禁用 csrf 以允许用户进行身份验证和授权,但仍然没有用。
谁能帮我解决这个问题。
您可以从 here 下载并查看完整的应用程序(根据最后建议 19/11/2017 更新)
更新 1
根据@fateddy 的建议,我使用 选项 3 使用 ApprovalStoreUserApprovalHandler。我使用了给定的确切 authorize.html。
假设我的数据库中有两个客户端(client123 和 client789)。
客户端 client123 没有启用自动批准,客户端 client789 为 [=40= 启用了自动批准选项]openid范围。
现在的问题是,当我单击批准按钮时,client123 出现以下异常。
error="invalid_client", error_description="错误的客户端凭据"
OAuth2Config.java如下
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Bean
public UserApprovalHandler userApprovalHandler() {
ApprovalStoreUserApprovalHandler userApprovalHandler= new ApprovalStoreUserApprovalHandler();
userApprovalHandler.setApprovalStore(approvalStore());
userApprovalHandler.setClientDetailsService(clientDetailsService());
userApprovalHandler.setRequestFactory(requestFactory());
return userApprovalHandler;
}
@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
@Bean
public DefaultOAuth2RequestFactory requestFactory(){
return new DefaultOAuth2RequestFactory(clientDetailsService());
}
@Bean
public ClientDetailsService clientDetailsService() {
return new JdbcClientDetailsService(dataSource);
}
@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
}
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Bean
public AuthorizationCodeServices authorizationCodeServices() {
return new JdbcAuthorizationCodeServices(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//endpoints.tokenStore(tokenStore());
// endpoints.approvalStore(approvalStore());
endpoints.userApprovalHandler(userApprovalHandler());
endpoints.authorizationCodeServices(authorizationCodeServices());
endpoints.authenticationManager(authenticationManager);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(dataSource);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer authorizationServerSecurityConfigurer) throws Exception {
authorizationServerSecurityConfigurer.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
}
authorize.html
<html>
<head>
</head>
<body>
<div class="container">
<h2>Please Confirm</h2>
<p>
Do you authorize "${authorizationRequest.clientId}" at "${authorizationRequest.redirectUri}" to access your protected resources
with scope ${authorizationRequest.scope?join(", ")}.
</p>
<form id="confirmationForm" name="confirmationForm" action="/auth/oauth/authorize" method="post">
<input name="scope.openid" value="true" type="checkbox" /> Read<br>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
</div>
</body>
</html>
参考是提供的project, git-commit 972b85
。
最后你有几个选择。但是让我们看一下当前的项目状态。
授权端点 (/oauth/authorize
) 让用户决定是授权还是拒绝访问(通过显示表单)。然后 UserApprovalHandler
决定是否授权。
现有的 UserAppovalHandler
- 实现需要不同的请求参数才能做出决定 - 这也意味着这会对 /oauth/authorize
- 视图的外观产生影响喜欢。
选项 1
自定义的 /oauth/authorize
-view 包含 <input name="user_oauth_approval" value="true" />
,它需要一个 UserApprovalHandler
来获取所述参数来做出决定。使用 DefaultUserApprovalHandler
(不记得任何决定)将起作用。配置可能如下所示。在这种情况下不需要 Approval-Store。
<form id="confirmationForm" name="confirmationForm"
action="/auth/oauth/authorize" method="post">
<input name="user_oauth_approval" value="true" type="hidden" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
user_oauth_approval=true
请求参数仅在使用 DefaultUserUserApprovalHandler
时才被拾取:
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Bean
UserApprovalHandler userApprovalHandler() {
return new DefaultUserApprovalHandler();
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// ...
endpoints.userApprovalHandler(userApprovalHandler());
}
}
选项 2
通过遵循选项 1,但在本例中,通过提供自定义 UserApprovalHandler
来记住任何决定。
选项 3
坚持使用 ApprovalStoreUserApprovalHandler
(在下面使用 TokenStore)需要对形式进行一些调整:
<form id="confirmationForm" name="confirmationForm" action="/auth/oauth/authorize" method="post">
<!--
The ApprovalStoreUserApprovalHandler tests scopes by testing request-params prefixed with `scope.*`
For dynamic input-element rendering one might iterate over
${authorizationRequest.scope}
Provides access to the scope=openid whenever the user checks the checkbox:
-->
<input name="scope.openid" value="true" type="checkbox" /> OpenID<br>
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
<button class="btn btn-primary" type="submit">Approve</button>
</form>
Auth-Server-Config:
@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(dataSource);
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
// ...
// registering an ApprovalStore automaticaly bootstraps `ApprovalStoreUserApprovalHandler`
endpoints.approvalStore(approvalStore());
}
}
选项 N
可能还有其他适合的选项 - 但这取决于您的要求。