Spring Security OAuth2詳解

一、OAuth2簡介

OAuth2是目前比較流行的授權協議,該協議用於允許第三方應用訪問用戶在某個應用上存儲的資源,而不需要將用戶名和密碼提供給第三方應用或者分享用戶的資源。授權過程中需要用戶授權預先定義的權限範圍。

OAuth2授權協議有四種角色,分別是:資源所有者、資源服務器、客戶端和授權服務器。其中,資源所有者指的是用戶本人,資源服務器指的是存儲着受保護資源的服務器,客戶端是請求資源的應用程序,授權服務器則是認證用戶並授予訪問資源的服務器。

二、Spring Security OAuth2基礎

1、Spring Security OAuth2實現授權的方式

Spring Security OAuth2提供了多種授權模式,包括授權碼授權模式、密碼授權模式、簡化授權模式、客戶端模式等。

2、Spring Security OAuth2結構

Spring Security OAuth2將OAuth2授權協議的四個角色抽象成四個模塊,包括客戶端、授權服務器、資源服務器和用戶認證的API。其中,第三方應用通過客戶端來請求授權服務器,授權服務器驗證用戶身份並返回訪問令牌,然後第三方應用通過攜帶訪問令牌請求資源服務器獲取受保護資源。

Spring Security OAuth2結構包括以下幾個核心組件:

  • AuthorizationEndpoint:授權端點處理授權請求,用戶通過授權端點認證自己並獲取訪問令牌。
  • TokenEndpoint:令牌端點用於生成和返回訪問令牌和刷新令牌。
  • TokenServices:用於生成訪問令牌。
  • ClientDetailsService:管理客戶端信息,包括客戶端ID、密鑰、授權範圍等。
  • UserDetailsService:管理用戶信息,包括用戶名、密碼和角色等。

三、Spring Security OAuth2與JWT

1、JWT簡介

JWT(JSON Web Token)是一種用於身份驗證和授權的Web標準,通過對JSON數據進行簽名和加密來實現安全的數據傳輸。Token是JWT最重要的概念,是一種輕量級的安全驗證憑證,在多個系統之間可以傳遞用於身份驗證。

2、Spring Security OAuth2結合JWT實現授權

Spring Security OAuth2默認使用基於Session-Stored Tokens的方式來管理令牌,但是在實際應用中,可以根據需要結合JWT來實現授權。

四、Spring Security OAuth2教程

1、基於授權碼的認證流程

授權碼授權模式是OAuth2中最常用的授權方式,具體步驟如下:

  @GetMapping("/login")
  public String loginPage(Map model) {
      return "login";
  }

  @Configuration
  @EnableAuthorizationServer
  public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Autowired
      private UserDetailsService userDetailsService;

      @Autowired
      private DataSource dataSource;

      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
          converter.setSigningKey("suztomo");
          return converter;
      }

      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
          clients.jdbc(dataSource);
      }

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

  @Configuration
  @EnableResourceServer
  public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

      @Autowired
      private JwtAccessTokenConverter accessTokenConverter;

      @Override
      public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .csrf().disable()
                  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and()
                  .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
      }

      @Override
      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          resources.tokenServices(tokenServices()).resourceId("resourceServer");
      }

      @Bean
      public ResourceServerTokenServices tokenServices() {
          RemoteTokenServices tokenServices = new RemoteTokenServices();
          tokenServices.setCheckTokenEndpointUrl("http://localhost:9090/oauth/check_token");
          tokenServices.setClientId("clientId");
          tokenServices.setClientSecret("clientSecret");
          tokenServices.setAccessTokenConverter(accessTokenConverter);
          return tokenServices;
      }

  }

2、基於密碼的認證流程

密碼授權模式是比較簡單的一種授權方式,具體步驟如下:

  @GetMapping("/login")
  public String loginPage(Map model) {
      return "login";
  }

  @Configuration
  @EnableAuthorizationServer
  public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Autowired
      private UserDetailsService userDetailsService;

      @Autowired
      private DataSource dataSource;

      @Bean
      public JwtAccessTokenConverter accessTokenConverter() {
          JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
          converter.setSigningKey("suztomo");
          return converter;
      }

      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
          clients.jdbc(dataSource);
      }

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

  @Configuration
  @EnableResourceServer
  public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

      @Autowired
      private JwtAccessTokenConverter accessTokenConverter;

      @Override
      public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .csrf().disable()
                  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and()
                  .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
      }

      @Override
      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          resources.tokenServices(tokenServices()).resourceId("resourceServer");
      }

      @Bean
      public ResourceServerTokenServices tokenServices() {
          RemoteTokenServices tokenServices = new RemoteTokenServices();
          tokenServices.setCheckTokenEndpointUrl("http://localhost:9090/oauth/check_token");
          tokenServices.setClientId("clientId");
          tokenServices.setClientSecret("clientSecret");
          tokenServices.setAccessTokenConverter(accessTokenConverter);
          return tokenServices;
      }

  }

3、基於客戶端的認證流程

客戶端授權模式是一種常見的OAuth2授權方式,具體步驟如下:

  @GetMapping("/login")
  public String loginPage(Map model) {
      return "login";
  }

  @Configuration
  @EnableAuthorizationServer
  public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {

      @Autowired
      private AuthenticationManager authenticationManager;

      @Autowired
      private DataSource dataSource;

      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
          clients.jdbc(dataSource);
      }

      @Override
      public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
          endpoints
                  .authenticationManager(authenticationManager)
                  .approvalStoreDisabled()
                  .tokenGranter(tokenGranter(endpoints))
                  .accessTokenConverter(accessTokenConverter());
      }

      private TokenGranter tokenGranter(final AuthorizationServerEndpointsConfigurer endpoints) {
          List granters = new ArrayList(Arrays.asList(endpoints.getTokenGranter()));
          granters.add(new ClientTokenGranter(endpoints.getTokenServices(), endpoints.getClientDetailsService(), endpoints.getOAuth2RequestFactory()));
          return new CompositeTokenGranter(granters);
      }

      @Bean
      public ClientDetailsService clientDetailsService() {
          JdbcClientDetailsService jdbcClientDetailsService = new JdbcClientDetailsService(dataSource);
          jdbcClientDetailsService.setPasswordEncoder(passwordEncoder());
          return jdbcClientDetailsService;
      }

      @Override
      public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
          clients.withClientDetails(clientDetailsService());
      }

  }

  @Configuration
  @EnableResourceServer
  public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

      @Autowired
      private JwtAccessTokenConverter accessTokenConverter;

      @Override
      public void configure(HttpSecurity http) throws Exception {
          http.authorizeRequests()
                  .anyRequest().authenticated()
                  .and()
                  .csrf().disable()
                  .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                  .and()
                  .exceptionHandling().authenticationEntryPoint(new Http403ForbiddenEntryPoint());
      }

      @Override
      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          resources.tokenServices(tokenServices()).resourceId("resourceServer");
      }

      @Bean
      public ResourceServerTokenServices tokenServices() {
          RemoteTokenServices tokenServices = new RemoteTokenServices();
          tokenServices.setCheckTokenEndpointUrl("http://localhost:9090/oauth/check_token");
          tokenServices.setClientId("clientId");
          tokenServices.setClientSecret("clientSecret");
          tokenServices.setAccessTokenConverter(accessTokenConverter);
          return tokenServices;
      }

  }

五、總結

Spring Security OAuth2是目前比較流行的授權協議之一,能夠幫助企業構建安全的互聯網應用。通過授權端點、令牌端點、客戶端和用戶認證的API等模塊,實現了OAuth2授權協議的四種角色。同時,Spring Security OAuth2還支持多種授權模式,包括授權碼授權模式、密碼授權模式、簡化授權模式和客戶端模式。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hk/n/300706.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-12-29 12:52
下一篇 2024-12-29 12:52

相關推薦

發表回復

登錄後才能評論