角度と春のセキュリティとKeyCloak


Keycloak 広くオープンソースのアイデンティティとアクセス管理アプリケーションの一つです.この記事では、KeyCloakの使用方法を、角度、スプリングブート、スプリングセキュリティの認証サーバーとして示します.いつものようにGithub repository

テクノロジー

  • スプリングブート2 .X
  • 治安
  • 角11 .X
  • keycloak 6.0.1
  • バネデータJPA
  • MySQL 5.7
  • ドック
  • 必要条件:

  • 指示に従ってくださいofficial docker documentation Dockerをローカルマシンにインストールします
  • この記事はKeyCloakとMySQL Dockerコンテナを設定します.しかし、スタンドアロンのバージョンを好む場合は、からの指示に従ってくださいofficial Keycloak docs KeyCloakをインストールし、ローカルMySQLサーバーにデータベースを作成するには
  • セットアップ

  • クローンGithub repository に移動し、/src/main/resources/docker ディレクトリ.
  • KeyCloakとMySQLコンテナを起動するには、次のコマンドを実行します
  • $ docker-compose -f keycloak-mysql.yml up
    
    3 . gohttp://localhost:8080 KeyCloak管理コンソールにログインし、次の資格情報を使用します.と同じkeycloak-mysql.yml コンテナを起動する前のファイル
    username: admin  
    password: Test@2020
    
    ホームページは次のようになります

    keycloak領域では、アクティブディレクトリのドメインに似ています.新しいグループまたはドメインを追加するには、マウスでマウスをポイントし、追加のrealmをクリックし、keycloakart

    ログインタブですべてを選択し、SSLexternal requests6 .クライアントをクリックして既存のクライアントの一覧を表示し、「Create」ボタンをクリックして新しいクライアントを作成しますangular-app選択angular-app クライアントリストから、次の値を[設定]タブで変更し、ページを保存します
    Valid Redirect URIs: [http://localhost:4200/\*](http://localhost:4200/*)  
    BaseU URL: [http://localhost:4200](http://localhost:4200)  
    Web Origins: \*
    
    8 .設定→ 役割→ 役割を加えて、ロレンマを与えますAdmin そして、あなたが異なる名前を使いたいならばsrc/main/java/com/pj/keycloak/security/Roles.java クラス
    役割ジャバ
    class Roles  
    {  
        static final String _ADMIN_\="Admin";  
    
        private Roles()  
        {  
    
        }  
    }
    
    9 .管理する→ 利用者→ ユーザーを追加し、以下のように値を入力します

    10 .ユーザーリストから作成したユーザーを選択し、資格情報タブに移動します.パスワードを設定するTest@2020

    11 .ロールマッピングをクリックし、管理者ロールを利用可能なロールから割り当てられたロールに取得する

    12 .ローカルのMySQLサーバに移動し、データベース名を作成するkeycloak-springsecurity. このデータベースはアプリケーションデータを保持します.これはKeyCloakデータベースとは異なる点に注意してください.

    どうやって走るの?

  • 移動するKeyCloakSpringSecurityApplication クラスを実行します.すべての期待通りに動作する場合は、残りのAPIを参照することができますhttp://localhost:8081
  • データベースサーバーに移動し、サンプルの従業員データを挿入するには、次のコマンドを実行します
  • INSERT INTO \`keycloak-springsecurity\`.\`employee\`  
    (\`id\`,\`email\`,\`first\_name\`,\`last\_name\`,\`phone\`) VALUES ([1001,'[email protected]](mailto:1001,'[email protected])','John','Doe','389-399-3893');
    
    3 . gosrc/main/webapp/spring-data-ui ディレクトリを作成し、以下のコマンドを実行して依存関係をインストールします
    $ npm install
    
    4 .角度アプリケーションを起動するには、次のコマンドを実行します.http://localhost:4200
    $  ng serve --watch
    
    http://localhost:4200 角のホームページを参照するには、自動的にKeyCloakのログインページにリダイレクトする必要があります.あなたが以前に作成したジョンDOEの資格情報を入力します.次の画面が表示されます

    アングルホームページ
    従業員のリストを見るために従業員をクリックしてください.それは、KeyCloakサーバーを介して保護された春のブートREST APIと角度のアプリです

    コードへのディープダイブ

  • まず春のコードを見てみましょう.我々は、以下のように定義されたいくつかの基本的なフィールドとコントローラ、サービス、リポジトリクラスを持つ従業員クラスを持っています
  • 従業員.ジャバ
    @Entity  
    @Table(name = "employee")  
    @Data  
    public class Employee implements Serializable  
    {  
        private static final long _serialVersionUID_ \= -2482579485413606056L;  
    
        @Id  
        @GeneratedValue(strategy = GenerationType._IDENTITY_)  
        private Long id;  
    
        @Column(name = "first\_name")  
        private String firstName;  
    
        @Column(name = "last\_name")  
        private String lastName;  
    
        @Column(name = "email")  
        private String email;  
    
        @Column(name = "phone")  
        private String phone;  
    
    
        @Override  
        public boolean equals(Object o)  
        {  
            if (this \== o)  
                return true;  
            if (o == null || getClass() != o.getClass())  
                return false;  
            Employee employee = (Employee) o;  
            return getId().equals(employee.getId());  
        }  
    
        @Override  
        public int hashCode()  
        {  
            return Objects._hash_(getId());  
        }  
    }
    
    株式会社ジャバ
    @RestController  
    @RequestMapping("/api/v1/employee")  
    public class EmployeeController  
    {  
        private final EmployeeService employeeService;  
    
        public EmployeeController(EmployeeService employeeService)  
        {  
            this.employeeService \= employeeService;  
        }  
    
        @GetMapping(path = "/list")  
        public List<Employee> findAll()  
        {  
            return employeeService.findAll();  
        }  
    
        @GetMapping(path = "/find/{id}")  
        public Optional<Employee> findById(@PathVariable Long id)  
        {  
            return employeeService.findById(id);  
        }  
    }
    
    (株)ジャバ
    @Service  
    public class EmployeeServiceImpl implements EmployeeService  
    {  
        private final EmployeeRepository employeeRepository;  
    
        public EmployeeServiceImpl(EmployeeRepository employeeRepository)  
        {  
            this.employeeRepository \= employeeRepository;  
        }  
    
        @Override  
        public List<Employee> findAll()  
        {  
            return employeeRepository.findAll();  
        }  
    
        @Override  
        public Optional<Employee> findById(Long id)  
        {  
            return employeeRepository.findById(id);  
        }  
    }
    
    雇い主ジャバ
    public interface EmployeeRepository extends JpaRepository<Employee,Long>  
    {  
    }
    
    2 . SecurityConfigクラスを使用してアプリケーションの安全性を管理しますKeycloakWebSecurityConfigurerAdapter KeyCloakによって確保されたWebSecurityConfigurerインスタンスを作成するための便利な基本クラスを提供するクラスです.この実装では、メソッドのオーバーライドでカスタマイズできます.
    3 .メソッドconfigureGlobal() ゲットKeyCloakAuthenticationAdapter インスタンスを設定しますkeycloakAuthenticationProvider. Spring Securityは、KeyCloakAuthenticationProviderを使用して認証を実行します
    @Autowired  
        public void configureGlobal(AuthenticationManagerBuilder authenticationManagerBuilder)  
        {  
            KeycloakAuthenticationProvider keycloakAuthenticationProvider=keycloakAuthenticationProvider();  
            keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper());  
            authenticationManagerBuilder.authenticationProvider(keycloakAuthenticationProvider);  
        }
    
    4 .豆KeycloakSpringBootConfigResolver KeyCloakからConfigプロパティに基づいて接続するのに役立ちますapplication.yml ファイル
    5 .configure( ) メソッドは、エンドポイントを必要なロールで確保するアプリケーション全体のキーです
    @Override  
    protected void configure(HttpSecurity http) throws Exception  
    {  
        super.configure(http);  
    
        http.authorizeRequests()  
                .antMatchers("/api/\*\*")  
                .hasAnyRole(Roles._ADMIN_)  
                .anyRequest()  
                .permitAll();  
    
        http.cors();  
    }
    
    6 .application.yml KeyCloakサーバのプロパティ、realmおよびクライアントの詳細が含まれます.
    _\# Server properties  
    _server:  
      port: 8081  
    
    _#Keycloak Properties  
    _keycloak:  
      auth-server-url: http://localhost:8080/auth  
      realm: keycloakdemo  
      resource: angular-app  
      public-client: true  
      principal-attribute: preferred\_username  
    .........  
    ......
    
    今、角のアプリケーションでは、KeyCloak JSライブラリを設定し、KeyCloakサーバーに接続し、認証を実行するのに役立ちます.サービスKeycloakService クラスは、KeyCloak JSライブラリクラスを使用してこれを達成し、アプリケーションを初期化するときに読み込みます
    キークローク.サービスTS
    import {Injectable} from "@angular/core";  
    import \* as _Keycloak_ from "keycloak-js";  
    import {KeycloakInstance} from "keycloak-js";  
    
    @Injectable({  
      providedIn: 'root'  
    })  
    export class KeycloakService  
    {  
      private keycloakAuth: KeycloakInstance;  
    
      constructor()  
      {  
      }  
    
      init(): Promise<any\>  
      {  
        return new _Promise_((resolve, reject) =>  
        {  
          const config = {  
            'url': 'http://localhost:8080/auth',  
            'realm': 'keycloakdemo',  
            'clientId': 'angular-app' };  
          _// @ts-ignore_ this.keycloakAuth \= new _Keycloak_(config);  
          this.keycloakAuth.init({onLoad: 'login-required'})  
              .success(() =>  
              {  
                resolve();  
              })  
              .error(() =>  
              {  
                reject();  
              });  
        });  
      }  
    
      getToken(): string {  
        return this.keycloakAuth.token;  
      }  
    
      logout()  
      {  
        const options = {  
          'redirectUri': 'http://localhost:4200',  
          'realm': 'keycloakdemo',  
          'clientId': 'angular-app' };  
        this.keycloakAuth.logout(options);  
      }  
    }
    
    8 . inapp.module.ts ファイルこのクラスを呼び出しますinit() アプリケーションの初期化
    export function _kcFactory_(keycloakService: KeycloakService) {  
      return () => keycloakService.init();  
    }  
    @NgModule({  
      declarations: \[  
        AppComponent,  
        EmployeeListComponent,  
        LogoutComponent  
      \],  
      imports: \[  
        BrowserModule,  
        AppRoutingModule,  
        HttpClientModule  
      \],  
      providers: \[KeycloakService,  
        {  
          provide: APP\_INITIALIZER,  
          useFactory: _kcFactory_,  
          deps: \[KeycloakService\],  
          multi: true },  
        {  
          provide: HTTP\_INTERCEPTORS,  
          useClass: TokenInterceptor,  
          multi: true }\],  
      bootstrap: \[AppComponent\]  
    })  
    export class AppModule { }
    
    9クラスTokenInterceptor 実装HttpInterceptor インターフェイスは、すべてのHTTPリクエストを傍受し、ベアラ認証トークンを設定するのに役立ちます.
    @Injectable()  
    export class TokenInterceptor implements HttpInterceptor  
    {  
      constructor(private kcService: KeycloakService)  
      {  
      }  
    
      intercept(request: HttpRequest<any\>, next: HttpHandler): Observable<HttpEvent<any\>>  
      {  
        const authToken = this.kcService.getToken() || "";  
        request = request.clone({  
          setHeaders: {  
            "Authorization": "Bearer " \+ authToken  
          }  
        });  
        return next.handle(request);  
      }  
    }
    
    すべてのコードを1つのリポジトリに結合し、アップロードGithub . ご質問がございましたらお知らせください.ハッピーコーディング