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。

假设我的数据库中有两个客户端(client123client789)。

客户端 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

可能还有其他适合的选项 - 但这取决于您的要求。