具有资源所有者密码凭据授权的Spring MVC和外部Oauth2服务器

时间:2018-01-10 13:53:48

标签: java spring spring-mvc spring-security oauth-2.0

我有一个spring MVC应用程序和一个远程OAuth2授权服务器。应使用远程服务器登录Web和移动应用程序,并授权微服务。用于授权的OAuth2服务器工作,当我直接调用获取令牌的路径时,该请求会正确返回访问和刷新令牌。

我的问题是我无法在Web应用程序中扩展WebSecurityConfigurerAdapter的类中配置HttpSecurity,以便使日志记录表单保留在应用程序中并使用密码grunt类型向远程OAuth2发送请求。因此loginProcessingUrl()不应该是默认j_spring_security_check,而应该是授权服务器的路径。我在http配置中使用addFilterBefore()无法实现这一点。

Spring Boot中Oauth2服务器应用程序上的AuthorizationServerConfigurerAdapter类看起来像这样:

package com.mydomain.oauth2.configuration;

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.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;

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

     @Autowired
     @Qualifier("userDetailsService")
     private UserDetailsService userDetailsService;

     @Autowired
     private AuthenticationManager authenticationManager;

     @Autowired
     private TokenStore tokenStore;

     @Bean
     public BCryptPasswordEncoder bCryptPasswordEncoder() {
          return new BCryptPasswordEncoder();
     }

     @Override
     public void configure( AuthorizationServerSecurityConfigurer oauthServer)  throws Exception {
          oauthServer
              .tokenKeyAccess("permitAll()")
              .checkTokenAccess("isAuthenticated()")
              .allowFormAuthenticationForClients();
     }

     @Override
     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
         clients
              .inMemory()
              .withClient("acme")
              .secret("acmesecret")
              .accessTokenValiditySeconds(3600)
              .scopes("read", "write")
              .redirectUris("http://localhost:8080/login")
              .authorizedGrantTypes("password", "refresh_token")
              .autoApprove(true)
              .resourceIds("resource");
      }

      @Override
      public void configure(AuthorizationServerEndpointsConfigurer configurer) throws Exception {
              configurer.authenticationManager(authenticationManager);
              configurer.userDetailsService(userDetailsService);
              configurer.tokenStore(tokenStore);
      }
}

我在Spring上编写的不是Spring Boot的Web应用程序的WebSecurityConfigurerAdapter类看起来像这样:

import java.util.Arrays;

import javax.servlet.Filter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter;
import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter;
import org.springframework.security.oauth2.client.resource.OAuth2ProtectedResourceDetails;
import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import com.humanbizz.web.security.UserInfoTokenServices;

@Configuration
@EnableWebSecurity
@EnableOAuth2Client
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private OAuth2ClientContextFilter oauth2ClientContextFilter;

    @Autowired
    OAuth2ClientContext oauth2ClientContext;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
       http
           .authorizeRequests()
           .antMatchers("/login*", "/forgot-password*", "/signup**", "/signup/**", "/resources/**", "/403", "/storage/api/download/**", "/test/public/**").permitAll()
           .antMatchers("/user**").anonymous()
           .anyRequest().authenticated()
      .and()
          .exceptionHandling().accessDeniedPage("/403")
      .and()
         .exceptionHandling()
      .and()
            .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("?")
            .usernameParameter("username")
            .passwordParameter("password")
            .defaultSuccessUrl("/")
            .failureUrl("/login?error=true")
      .and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
      .and()
            .logout().logoutSuccessUrl("/login").deleteCookies("JSESSIONID")
      .and()
            .addFilterBefore( myFilter(), BasicAuthenticationFilter.class);
     }

     private Filter myFilter() throws Exception{
        OAuth2ClientAuthenticationProcessingFilter myFilter = new OAuth2ClientAuthenticationProcessingFilter("/login");
        OAuth2RestTemplate myTemplate = new OAuth2RestTemplate(template(), oauth2ClientContext);
        teodeskFilter.setRestTemplate(myTemplate);    

        UserInfoTokenServices tokenServices = new UserInfoTokenServices("http://localhost:9000/user", "acme");
        tokenServices.setRestTemplate(myTemplate);
        teodeskFilter.setTokenServices(tokenServices);

        return myFilter;
    }

    @Bean
    public OAuth2ProtectedResourceDetails template() {
        AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails();
        details.setClientId("acme");
        details.setClientSecret("acmesecret");
        details.setAccessTokenUri("http://localhost:9000/oauth/token"); details.setUserAuthorizationUri("http://localhost:9000/oauth/authorize");
        details.setGrantType("password");
        details.setScope(Arrays.asList("read"));

       return details;
   }

}

我的问题是如何配置过滤器以使用表单和密码grunt类型正确获取令牌。表单位于Web应用程序上,应该向远程auth服务器发出请求。我遇到的示例主要与Spring Boot有关,或者由Authorization Server和Resource Server在同一个应用程序中共同解决。

0 个答案:

没有答案