Spring Cloud OAuth2 は、Spring Cloud システムの OAuth2 プロトコルの実装であり、複数のマイクロサービスの統合認証 (アイデンティティの正当性の検証) と認可 (アクセス許可の検証) に使用できます。特定のタイプのgrant_typeをOAuth2サービス(統合認証・認可サービス)に送信して一元的な認証・認可を行うことでaccess_token(アクセストークン)を取得し、このトークンが他のマイクロサービスから信頼されます。
- セッションベースの認証方式
分散環境では、セッション ベースの認証によって問題が発生します。各アプリケーション サービスは
、ユーザー ID 情報をセッションに保存する必要があります。ロード バランシングを通じてローカル リクエストを別のアプリケーション サービスに分散するには
再認証されます。セッション共有やセッション貼り付けなどのソリューションを使用できます
- トークンベースの認証方式
トークンベースの認証方式では、サーバーは認証データを保存する必要がなく、保守が容易で拡張性が高く、クライアントは任意の場所にトークンを保存でき、Webとアプリで統一された認証メカニズムを実装できます
。欠点も明らかで、トークンには自己完結型の情報が含まれるため、
一般にデータ量が大きく、リクエストごとに送信する必要があるため、多くの帯域幅を消費します。さらに、トークン署名検証操作により、
CPU に追加の処理負荷がかかります。
OAuth2の概要
OAuth (Open Authorization) は、ユーザー名とパスワードをサードパーティ アプリケーションに提供したり、データのすべてのコンテンツを共有したりすることなく、サードパーティ アプリケーションが別のサービス プロバイダーに保存されている情報にアクセスすることを承認できるオープン プロトコル/標準です。
- リソース所有者: ユーザー自身として理解できます
- クライアント: Lagou.com など、ログインしたい Web サイトまたはアプリケーション
- 認可サーバー: WeChat または QQ として理解できます。
- リソース サーバー: WeChat または QQ として理解できます。
OAuth2のトークン認証方式
- 認可コード
- パスワードは、トークンと引き換えにユーザー名とパスワードを提供します。
- 暗黙
- クライアントの資格情報
認証サーバー(認可サーバー)を構築する
トークンの発行を担当する認可サーバー
- m-parent に基づいて新しいプロジェクト m-cloud-oauth-server-9999 を作成します。
- pom.xml
<!--导⼊Eureka Client依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!--导⼊spring cloud oauth2依赖-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth.boot</groupId>
<artifactId>spring-security-oauth2-autoconfigure</artifactId>
<version>2.1.11.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
- application.yml (認証サーバーを構築します。設定ファイルには特別なものはありません)
server:
port: 9999
spring:
application:
name: m-cloud-oauth-server
#注册发现
eureka:
client:
service-url:
defaultZone: http://CloudEurekaServerA:8761/eureka,http://CloudEurekaServerB:8762/eureka
instance:
prefer-ip-address: true
instance-id: ${
spring.cloud.client.ip-address}:${
spring.application.name}:${
server.port}:@project.version@
- スタートアップクラス
@SpringBootApplication
@EnableDiscoveryClient
@EnableAuthorizationServer //开启认证服务器功能
public class MCloudOuathServer9999 {
public static void main(String[] args) {
SpringApplication.run(MCloudOuathServer9999.class, args);
}
}
- 構成クラス
- 認証サーバー構成クラス
package com.w.edu.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
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.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.InMemoryTokenStore;
@Configuration
public class OauthServerConfiger extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
/**
* 认证服务器最终以api接口方式对外提供服务(生成令牌、校验令牌)
*
* @param security
* @throws Exception
*/
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
super.configure(security);
security
//允许客户端表单认证
.allowFormAuthenticationForClients()
//开启端口/oauth/token_key的访问权限
.tokenKeyAccess("permitAll()")
//开启端口/oauth/check_token的访问权限
.checkTokenAccess("permitAll()");
}
/**
* 客户端吧详情配置
*
* @param clients
* @throws Exception
*/
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
super.configure(clients);
//客户端信息存储在什么地方,既可以在内存也可以在数据库里
clients.inMemory()
//添加客户端配置。指定client_id
.withClient("client_w")
//指定客户端密码、安全码
.secret("abcdef")
//指定客户端可访问的资源id 清单
.resourceIds("autodeliver")
//认证类型、客户端令牌颁发模式//认证模式。可以配置多个
.authorizedGrantTypes("password", "refresh_token")
//客户端权限范围,配置all 即可
.scopes("all");
}
/**
* Token 令牌管理相关
*
* @param endpoints
* @throws Exception
*/
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
super.configure(endpoints);
endpoints
//token 存储方式
.tokenStore(tokenStore())
//配置token细节
.tokenServices(authorizationServerTokenServices())
//认证管理器
.authenticationManager(authenticationManager)
.allowedTokenEndpointRequestMethods(HttpMethod.GET, HttpMethod.POST);
}
/**
* Token 存储方式
*
* @return
*/
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
/**
* 获取Token服务对象,描述token有效期等信息
*
* @return
*/
public AuthorizationServerTokenServices authorizationServerTokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
//开启令牌刷新
defaultTokenServices.setSupportRefreshToken(Boolean.TRUE);
//
defaultTokenServices.setTokenStore(tokenStore());
//设置令牌有效时间(一半2小时)
defaultTokenServices.setAccessTokenValiditySeconds(20);
//设置令牌的有效时间
defaultTokenServices.setRefreshTokenValiditySeconds(259200);
return defaultTokenServices;
}
}
- セキュリティ構成クラス
package com.w.edu.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.ArrayList;
/**
* @author Mrwg
* @date 2023/4/13 20:30
* @description
* 处理用户名和密码的校验
*/
@Configuration
public class SecurityConfiger extends WebSecurityConfigurerAdapter {
/**
*注入AuthenticationManager
* @return
* @throws Exception
*/
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Bean
public PasswordEncoder passwordEncoder(){
return NoOpPasswordEncoder.getInstance();
}
/**
* 处理用户名密码事宜
* 1 客户传递username 和password 参数到认证服务器
* 2一半存储在数据表中
* 3 根据用户传递的数据,验证当前传递过来用户信息的合法性
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 实例化用户对象
UserDetails user = new User("admin","123456",new ArrayList<>());
auth.inMemoryAuthentication()
.withUser(user).passwordEncoder( passwordEncoder());
}
}
- テスト
- 取得トークン
http://localhost:9999/oauth/token?client_secret=abcdef&grant_type=password&username=admin&password=123456&client_id=client_w- エンドポイント:/oauth/token
- トークンによって運ばれるパラメータを取得します
client_id : クライアント ID
client_secret : クライアントの単一パスワード
Grant_type : 使用する発行タイプ、パスワードを指定します
username : ユーザー名
password : パスワード
- 校验トークン
http://localhost:9999/oauth/check_token?token=83964ab2-9b37-4c8f-8f4c-1c37a496b902
- 新しいトークン
http://localhost:9999/oauth/token?grant_type=refresh_token&client_id=client_w&client_secret=abcdef&refresh_token=06c1da97-452f-41ff-a597-89892e43ee49
リソースサーバーの構築(リソースサーバー)
- リフォーム
m-service-autodeliver-8092
サービス - 依存関係
認証サーバー OAuth2 依存関係をm-service-autodeliver-8092
サービスに追加します - application.yml
の新しい構成
oauth2:
server:
check-token-url: http://localhost:9999/check_token
- テストコントローラーの追加
@RestController
@RequestMapping("/demo")
public class DemoController {
/**
* 使用Feign
*
* @param userId
* @return
*/
@GetMapping("/test")
public String findResumeOpenState() {
return "demo/test";
}
}
@RestController
@RequestMapping("/other")
public class OtherController {
/**
* 使用Feign
*
* @param userId
* @return
*/
@GetMapping("/test")
public String findResumeOpenState() {
return "other/test";
}
}
- サービスを開始して確認する
- 認証は必要ですが、インターフェイスにアクセスするための許可は必要ありません。
- 認証やインターフェースへのアクセス許可は必要ありません
- トークンによるアクセス
- トークンの取得
- アクセスインターフェース
- トークンの取得
考える
考え方: 初めてログインするときに、認証サーバーはトークンを発行して認証サーバーに保存します。その後、リソースサーバーにアクセスするときにトークンを持ち歩きます。リソースサーバーは認証サーバーに検証を要求します。トークンの有効性. リソース サーバーが多数ある場合、認証サーバーは大きな負荷を受けることになります...
変換には JWT を使用します。JWT メカニズムを使用すると、リソース サーバーは認証サーバーにアクセスする必要がなくなります。