簡體   English   中英

Spring - 遠程基本認證

[英]Spring - Remote Basic Authentication

我正在將 Monolith Java/Spring 服務器重寫為微服務,同時向客戶端公開相同的 API 接口,因此他們不會注意到發生了任何更改。

在 Monolith 服務器中,我們使用Spring-SecuritySpring-Security-OAuth2

第一部分是創建一個基於 Java 的 API 網關,它將處理所有身份驗證/授權作為通往 Monolith 服務器的隧道。

創建新的微服務后(使用 spring initializr),我嘗試配置 spring 安全性以使用以下方式將所有身份驗證隧道傳輸到 Monolith 服務器:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final AuthenticationProvider authenticationProvider;

    public WebSecurityConfig(AuthenticationProvider authenticationProvider) {
        this.authenticationProvider = authenticationProvider;
    }
}
@Component("authenticationProvider")
public class CustomRemoteAuthenticationProvider extends RemoteAuthenticationProvider {

    @Override
    @Autowired
    @Qualifier("remoteAuthenticationManager")
    public void setRemoteAuthenticationManager(RemoteAuthenticationManager remoteAuthenticationManager) {
        super.setRemoteAuthenticationManager(remoteAuthenticationManager);
    }

}
@Service("remoteAuthenticationManager")
public class CustomRemoteAuthenticationManager implements RemoteAuthenticationManager {

    @Override
    public Collection<? extends GrantedAuthority> attemptAuthentication(String username, String password) throws RemoteAuthenticationException {
        ... here I do an HTTP call to the Monolith `/oauth/login`
    }
}

當我訪問 spring-security 的http://localhost:8080/login頁面時,這似乎有效,我可以成功登錄,並且請求通過隧道傳輸到我們的 Monolith 服務器。

當我嘗試配置OAuth2資源服務器時,問題就開始了,因為我們的客戶端當前使用 Header 中的一些基本身份驗證使用 POST 到oauth/token進行身份驗證:

Basic xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

注意:基本的令牌是所有客戶端的 static 令牌(我知道它沒有任何價值,但這是目前實現的方式,我嘗試實現完全兼容的 API 網關)

這允許他們與該端點進行通信並為正文中的用戶/密碼獲取有效令牌(即 application/x-www-form-urlencoded):

password=somepassword&username=user@example.com&grant_type=password&scope=read%20write

問題是 spring-security 為該調用返回401 Unauthorized ,甚至沒有讓請求進入/oauth/login路由並進行遠程身份驗證。

我找不到將基本身份驗證隧道傳輸到單體服務器的方法,因此/oauth/login實際上將使用遠程基本身份驗證對單體進行身份驗證,成功后它將充當隧道並將主體本身傳遞到單體/oauth/login端點(正如我在上面的WebSecurityConfig中成功完成的那樣)

任何方向將不勝感激。 提前致謝!

我正在做一個類似的項目,我認為我可以為您提供一些指導。

OAuth2 是基於令牌的安全授權和身份驗證,我們可以分為四個組件:

  1. 受保護的資源(只能由具有適當授權的經過身份驗證的用戶訪問)
  2. 資源所有者(定義哪些應用程序可以調用他們的服務,哪些用戶可以訪問該服務以及他們可以做什么)
  3. 應用程序(是代表用戶調用服務的應用程序)
  4. OAuth2 身份驗證服務(位於應用程序和受保護資源之間)

在您的情況下,受保護的資源是您想要在微服務架構中打破的單體。

  • 您需要做的第一件事是創建授權服務。

從 spring intilizr 創建 SpringCloud 項目,確保存在以下依賴項:

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-oauth2</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-security</artifactId>
        </dependency>

之后,在 oauth2 服務的主要 class 中,您需要添加兩個注釋。 @EnableResourceServer用於告訴您的微服務是受保護的資源。 我將在下面解釋為什么需要這樣做。 @EnableAuthorizationServer將告訴 spring 雲服務將用作 OAuth2Service。 下面是代碼片段:

@SpringBootApplication
@EnableResourceServer
@EnableAuthorizationServer
public class Oauth2ServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(Oauth2ServerApplication.class, args);
    }

}

我們創建一個將公開用戶信息的端點。 該端點將被其他服務調用。 這就是我們使用@EnableResourceServer注釋此應用程序的原因。 以下是返回用戶信息的 rest 端點:

@RestController
@RequestMapping("/user")
public class UserRestController {

    @GetMapping(produces="application/json")
    public Map<String,Object> getUser(OAuth2Authentication user){
        Map<String,Object> userInfo = new HashMap<>();
        userInfo.put("user",user.getUserAuthentication().getPrincipal());
        userInfo.put("authorities", user.getUserAuthentication().getAuthorities());
        return userInfo;
    }

}

現在您將在 oauth2 服務中注冊應用程序。 您將定義將訪問受保護資源的應用程序。 您將創建一個配置 class 來定義哪些應用程序可以使用您的服務。

@Configuration
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private AuthenticationManager authenticationManager;
    @Autowired
    private UserDetailsService userDetailsService;
    @Autowired
    private PasswordEncoder passwordEncoder;
    @Autowired
    OAuth2ConfigParameters oauth2ConfigParameters;

    @Bean
    public OAuth2ConfigParameters oAuth2ConfigParameters() {
        return new OAuth2ConfigParameters();
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
        endpoints
                .authenticationManager(authenticationManager)
                .userDetailsService(userDetailsService);
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
        .withClient("your application")
        .secret("your password")
        .authorizedGrantTypes( "refresh_token","password","client_credentials")
        .scopes("webclient","mobileclient");
    }
}

您需要定義應用程序的用戶和角色。 如果您已經使用 SpringBoot 完成了安全性,這很熟悉。 檢查下面的代碼段:

@Configuration
public class WebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    @Bean
    public UserDetailsService userDetailsServiceBean() throws Exception {
        return super.userDetailsServiceBean();
    }

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

    @Override 
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
        .withUser("you user")
        .password(passwordEncoder().encode("your password"))
        .roles("your role");
    }
}

最后檢查 postman 是否可以從 oauth2 服務檢索令牌。

HttpMethod :POST, URLhttp://localhost:application-port/oauth/token

授權類型:基本,用戶名:客戶端 ID,密碼:客戶端密碼

正文:表單數據,

授予:密碼

scope:webclient

用戶名:您的用戶名

密碼:您的密碼

檢索令牌后,測試您是否可以訪問該令牌,即您公開用戶信息的端點的 URL。

HttpMethod :獲取, URL :本地主機:應用程序端口/用戶

Authorization : Bearer, Token : 生成的令牌


  • 其次,保護將從網關服務器訪問的舊單體。 請記住,您的舊單體是受保護的資源。

首先,您需要將 Spring Security 和 OAuth2 jars 添加到您要保護的服務中。

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>

接下來在單體應用程序的 application.yml 中,我們配置您的 oauth2 服務的服務點。 這樣做是因為單體應用是受保護的服務,每次收到請求時,您都想檢查請求的令牌是否有效。

security:
 oauth2:
  resource:
   userInfoUri: http://localhost:oauth2-app-port/auth/user

之后不要忘記添加@EnableResourceServer ,這會使單體成為受保護的資源。


@SpringBootApplication
@EnableResourceServer
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

之后,我們指定我們想要的限制。 我在下面提供了限制僅對經過身份驗證的用戶進行訪問的示例。

@Configuration
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated();
    }
}

  • 回顧

您的用戶已通過 OAuth 服務進行身份驗證,並具有生成的令牌。 使用生成的令牌通過網關服務器向單體發送請求。 網關嘗試通過傳播它從請求中收到的令牌來訪問單體。 單體檢查令牌是否有效。

下面是我的微服務架構與zuul網關服務器和oauth2服務器的鏈接: https://github.com/rshtishi/payroll 如果您想查看更多詳細信息,可以檢查它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM