Spring Boot ず OAuth2

このガむドでは、OAuth 2.0 [IETF] (英語) および Spring Boot を䜿甚しお「゜ヌシャルログむン」でさたざたなこずを行うサンプルアプリを䜜成する方法を瀺したす。

シンプルなシングルプロバむダヌシングルサむンオンから始たり、認蚌プロバむダヌを遞択したクラむアントGitHub (英語) たたは Google (英語) たで機胜したす。

サンプルはすべお、バック゚ンドで Spring Boot ず Spring Security を䜿甚するシングルペヌゞアプリです。たた、フロント゚ンドではプレヌンな jQuery (英語) を䜿甚しおいたす。ただし、別の JavaScript フレヌムワヌクに倉換したり、サヌバヌ偎レンダリングを䜿甚したりするために必芁な倉曎は最小限です。

すべおのサンプルは、Spring Boot (英語) のネむティブ OAuth 2.0 サポヌトを䜿甚しお実装されたす。

いく぀かのサンプルが盞互に構築されおおり、各ステップで新しい機胜が远加されおいたす。

  • simple: ホヌムペヌゞず Spring Boot の OAuth 2.0 構成プロパティを介した無条件のログむンを備えた非垞に基本的な静的アプリホヌムペヌゞにアクセスするず、自動的に GitHub にリダむレクトされたす。

  • click: ナヌザヌがログむンするためにクリックする必芁がある明瀺的なリンクを远加したす。

  • logout: 認蚌されたナヌザヌのログアりトリンクも远加したす。

  • two-providers: ナヌザヌがホヌムペヌゞで䜿甚するものを遞択できるように、2 番目のログむンプロバむダヌを远加したす。

  • custom-error: 認蚌されおいないナヌザヌ向けの゚ラヌメッセヌゞず、GitHub の API に基づくカスタム認蚌を远加したす。

機胜ラダヌ内のあるアプリから次のアプリに移行するために必芁な倉曎は、゜ヌスコヌド [GitHub] (英語) で远跡できたす。アプリの各バヌゞョンは独自のディレクトリであるため、違いを比范できたす。

各アプリは IDE にむンポヌトできたす。SocialApplication ã§ main ãƒ¡ã‚œãƒƒãƒ‰ã‚’実行しおアプリを起動できたす。それらはすべお、http://localhost:8080 にホヌムペヌゞを䜜成したす (ログむンしおコンテンツを衚瀺するには、少なくずも GitHub および Google アカりントを持っおいる必芁がありたす)。

たた、mvn spring-boot:run ã‚’䜿甚しお、たたは jar ファむルを䜜成しお mvn package ãŠã‚ˆã³ java -jar target/*.jar ã§å®Ÿè¡Œã™ã‚‹ã“ずにより、コマンドラむンですべおのアプリを実行できたすSpring Boot ドキュメント (英語) およびその他の利甚可胜なドキュメントに埓っお。最䞊䜍でラッパヌ [GitHub] (英語) を䜿甚する堎合、Maven をむンストヌルする必芁はありたせん。たずえば

$ cd simple
$ ../mvnw package
$ java -jar target/*.jar
アプリはすべお、そのアドレスの GitHub および Google に登録された OAuth 2.0 クラむアントを䜿甚するため、localhost:8080 ã§å‹•䜜したす。別のホストたたはポヌトでアプリを実行するには、そのようにアプリを登録する必芁がありたす。デフォルト倀を䜿甚する堎合、ロヌカルホストを超えお資栌情報が挏掩する危険はありたせん。ただし、䜕をむンタヌネットに公開するかには泚意し、独自のアプリ登録をパブリック゜ヌス管理に眮かないでください。

GitHub でのシングルサむンオン

このセクションでは、認蚌に GitHub を䜿甚する最小限のアプリケヌションを䜜成したす。これは、Spring Boot の自動構成機胜を利甚するこずにより、非垞に簡単になりたす。

新しいプロゞェクトを䜜成する

たず、Spring Boot アプリケヌションを䜜成する必芁がありたすが、これはさたざたな方法で実行できたす。最も簡単な方法は、https://start.spring.io に移動しお空のプロゞェクトを生成するこずです開始点ずしお "Web" 䟝存関係を遞択したす。同様に、コマンドラむンでこれを実行したす。

$ mkdir ui && cd ui
$ curl https://start.spring.io/starter.tgz -d style=web -d name=simple | tar -xzvf -

その埌、そのプロゞェクトをお気に入りの IDEデフォルトでは通垞の Maven Java プロゞェクトにむンポヌトするか、コマンドラむンでファむルず mvn ã‚’操䜜するだけです。

ホヌムペヌゞを远加する

新しいプロゞェクトで、src/main/resources/static ãƒ•ォルダヌに index.html ã‚’䜜成したす。結果が次のようになるように、スタむルシヌトず JavaScript リンクを远加する必芁がありたす。

index.html
<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta http-equiv="X-UA-Compatible" content="IE=edge"/>
    <title>Demo</title>
    <meta name="description" content=""/>
    <meta name="viewport" content="width=device-width"/>
    <base href="/"/>
    <link rel="stylesheet" type="text/css" href="/webjars/bootstrap/css/bootstrap.min.css"/>
    <script type="text/javascript" src="/webjars/jquery/jquery.min.js"></script>
    <script type="text/javascript" src="/webjars/bootstrap/js/bootstrap.min.js"></script>
</head>
<body>
	<h1>Demo</h1>
	<div class="container"></div>
</body>
</html>

OAuth 2.0 ログむン機胜をデモンストレヌションするためにこれは必芁ありたせんが、最埌に快適な UI を甚意するのは良いこずなので、ホヌムペヌゞの基本的なものから始めるこずもできたす。

アプリを起動しおホヌムペヌゞを読み蟌むず、スタむルシヌトが読み蟌たれおいないこずに気が付くでしょう。そのため、jQuery ず Twitter Bootstrap を远加しお、これらも远加する必芁がありたす。

pom.xml
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>jquery</artifactId>
	<version>3.4.1</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>bootstrap</artifactId>
	<version>4.3.1</version>
</dependency>
<dependency>
	<groupId>org.webjars</groupId>
	<artifactId>webjars-locator-core</artifactId>
</dependency>

最埌の䟝存関係は、webjars サむトによっおラむブラリずしお提䟛される webjars「ロケヌタヌ」です。Spring はロケヌタヌを䜿甚しお、正確なバヌゞョンを知る必芁なく webjar 内の静的アセットを芋぀けるこずができたすしたがっお、index.html のバヌゞョンレス /webjars/** ãƒªãƒ³ã‚¯ïŒ‰ã€‚MVC 自動構成をオフにしない限り、Spring Boot アプリでは webjar ロケヌタヌがデフォルトでアクティブになりたす。

これらの倉曎が適切に行われるず、アプリの芋栄えの良いホヌムペヌゞが䜜成されたす。

GitHub および Spring Security を䜿甚したアプリケヌションの保護

アプリケヌションを安党にするために、Spring Security を䟝存関係ずしお単玔に远加できたす。「゜ヌシャル」ログむンGitHub ぞのデリゲヌトを行うため、Spring Security OAuth 2.0 Client スタヌタヌを含める必芁がありたす。

pom.xml
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-oauth2-client</artifactId>
</dependency>

それを远加するこずで、デフォルトで OAuth 2.0 でアプリを保護したす。

次に、GitHub を認蚌プロバむダヌずしお䜿甚するようにアプリを構成する必芁がありたす。これを実珟するには、次を実行したす。

新しい GitHub アプリを远加する

ログむンに GitHub の OAuth 2.0 認蚌システムを䜿甚するには、最初に新しい GitHub アプリを远加する (英語) を行う必芁がありたす。

新しい OAuth アプリを遞択するず、新しい OAuth アプリケヌションの登録ペヌゞが衚瀺されたす。アプリの名前ず説明を入力したす。次に、アプリのホヌムペヌゞこの堎合は http://localhost:8080を入力したす。最埌に、認可コヌルバック URL を http://localhost:8080/login/oauth2/code/github ãšã—お指定し、アプリケヌションの登録をクリックしたす。

OAuth リダむレクト URI は、゚ンドナヌザヌのナヌザヌ゚ヌゞェントが GitHub で認蚌され、アプリケヌションの承認ペヌゞでアプリケヌションぞのアクセスを認可した埌にリダむレクトされるアプリケヌション内のパスです。

デフォルトのリダむレクト URI テンプレヌトは {baseUrl}/login/oauth2/code/{registrationId} です。registrationId は、ClientRegistration の䞀意の識別子です。

application.yml を構成する

次に、GitHub ぞのリンクを䜜成するには、以䞋を application.yml に远加したす。

application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: github-client-id
            clientSecret: github-client-secret
# ...

GitHub で䜜成したばかりの OAuth 2.0 資栌情報を䜿甚し、github-client-id ã‚’クラむアント ID に、github-client-secret ã‚’クラむアントシヌクレットに眮き換えるだけです。

アプリケヌションを起動する

この倉曎により、アプリを再床実行しお http://localhost:8080 のホヌムペヌゞにアクセスできたす。これで、ホヌムペヌゞの代わりに、GitHub でのログむンにリダむレクトされるはずです。それを行い、行うように求められた認可を受け入れるず、ロヌカルアプリにリダむレクトされ、ホヌムペヌゞが衚瀺されたす。

GitHub にログむンしたたたにするず、Cookie やキャッシュデヌタのない新しいブラりザヌで開いおも、このロヌカルアプリで再認蚌する必芁はありたせん。(それがシングルサむンオンの意味です。)

このセクションでサンプルアプリケヌションを䜿甚しおいる堎合は、ブラりザヌのキャッシュの Cookie ず HTTP 基本認蚌情報を必ずクリアしおください。単䞀のサヌバヌでこれを行う最良の方法は、新しいプラむベヌトりィンドりを開くこずです。

ロヌカルで実行されおいるアプリのみがトヌクンを䜿甚でき、芁求されるスコヌプが制限されおいるため、このサンプルぞのアクセスを蚱可しおも安党です。ただし、このようなアプリにログむンするずきは、承認する内容に泚意しおください。アプリは、あなたに必芁以䞊の蚱可を求める堎合がありたす (たずえば、個人デヌタを倉曎する蚱可を求めるかもしれたせんが、これはあなたの䞍利益になる可胜性がありたす)。

䜕が起こっおいるのか

OAuth 2.0 の甚語で蚘述したアプリはクラむアントアプリケヌションであり、認蚌コヌド付䞎 [IETF] (英語) を䜿甚しお GitHub認蚌サヌバヌからアクセストヌクンを取埗したす。

次に、アクセストヌクンを䜿甚しお、ログむン ID や名前などの個人的な詳现蚱可した操䜜のみを GitHub に芁求したす。このフェヌズでは、GitHub はリ゜ヌスサヌバヌずしお機胜し、送信したトヌクンをデコヌドし、ナヌザヌの詳现ぞのアクセスをアプリに蚱可するかどうかを確認したす。そのプロセスが成功するず、アプリはナヌザヌの詳现を Spring Security コンテキストに挿入しお、ナヌザヌが認蚌されるようにしたす。

ブラりザヌツヌルChrome たたは Firefox の F12を調べお、すべおのホップのネットワヌクトラフィックを远跡するず、GitHub で前埌にリダむレクトが衚瀺され、最終的に新しい Set-Cookie ã§ãƒ›ãƒŒãƒ ãƒšãƒŒã‚žã«æˆ»ã‚ŠãŸã™ã€‚ヘッダヌ。この Cookieデフォルトでは JSESSIONIDは、Springたたはサヌブレットベヌスのアプリケヌションの認蚌詳现のトヌクンです。

ナヌザヌが倖郚プロバむダヌGitHubで認蚌する必芁があるコンテンツを衚瀺するずいう意味で、安党なアプリケヌションがありたす。

むンタヌネットバンキングの Web サむトにこれを䜿甚したくないでしょう。しかし、基本的な識別の目的のため、サむトの異なるナヌザヌ間でコンテンツを分離するために、優れた出発点です。そのため、この皮の認蚌は最近非垞に人気がありたす。

次のセクションでは、アプリケヌションにいく぀かの基本的な機胜を远加したす。たた、GitHub ぞの最初のリダむレクトを取埗したずきに䜕が起こっおいるのかをナヌザヌに少しわかりやすくしたす。

ようこそペヌゞを远加する

このセクションでは、GitHub でログむンするための明瀺的なリンクを远加しお、䜜成した単玔なアプリを倉曎したす。すぐにリダむレクトされる代わりに、新しいリンクがホヌムペヌゞに衚瀺され、ナヌザヌはログむンするか、認蚌されないたたにするかを遞択できたす。ナヌザヌがリンクをクリックした堎合にのみ、安党なコンテンツがレンダリングされたす。

ホヌムペヌゞの条件付きコンテンツ

ナヌザヌが認蚌されおいるずいう条件でコンテンツをレンダリングするには、サヌバヌ偎たたはクラむアント偎のレンダリングのオプションがありたす。

ここでは、JQuery (英語) を䜿甚しおクラむアント偎を倉曎したすが、他のものを䜿甚する堎合は、クラむアントコヌドを倉換するのはそれほど難しくないはずです。

動的コンテンツを開始するには、次のような HTML 芁玠をいく぀かマヌクする必芁がありたす。

index.html
<div class="container unauthenticated">
    With GitHub: <a href="/oauth2/authorization/github">click here</a>
</div>
<div class="container authenticated" style="display:none">
    Logged in as: <span id="user"></span>
</div>

デフォルトでは、最初の <div> ãŒè¡šç€ºã•れ、2 番目の <div> ã¯è¡šç€ºã•れたせん。id å±žæ€§ã‚’持぀空の <span> ã«ã‚‚泚意しおください。

すぐに、ログむンしたナヌザヌの詳现を JSON ずしお返すサヌバヌ偎の゚ンドポむントを远加したす。

ただし、最初に、その゚ンドポむントにヒットする次の JavaScript を远加したす。゚ンドポむントのレスポンスに基づいお、この JavaScript は <span> ã‚¿ã‚°ã«ãƒŠãƒŒã‚¶ãƒŒåã‚’入力し、<div> ã‚’適切に切り替えたす。

index.html
<script type="text/javascript">
    $.get("/user", function(data) {
        $("#user").html(data.name);
        $(".unauthenticated").hide()
        $(".authenticated").show()
    });
</script>

この JavaScript は、サヌバヌ偎の゚ンドポむントが /user ず呌ばれるこずを期埅しおいるこずに泚意しおください。

/user ã‚šãƒ³ãƒ‰ãƒã‚€ãƒ³ãƒˆ

ここで、䞊蚘のサヌバヌ偎の゚ンドポむントを远加しお、/user ず呌びたす。珟圚ログむンしおいるナヌザヌを送り返したす。これは、メむンクラスで非垞に簡単に実行できたす。

SocialApplication.java
@SpringBootApplication
@RestController
public class SocialApplication {

    @GetMapping("/user")
    public Map<String, Object> user(@AuthenticationPrincipal OAuth2User principal) {
        return Collections.singletonMap("name", principal.getAttribute("name"));
    }

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

}

ハンドラヌメ゜ッドに挿入された @RestController、@GetMapping、OAuth2User ã®äœ¿ç”šã«æ³šæ„ã—おください。

゚ンドポむントに OAuth2User å…šäœ“を返すこずは、ブラりザヌクラむアントには公開したくない情報が含たれおいる可胜性があるため、玠晎らしいアむデアではありたせん。

ホヌムペヌゞを公開する

最埌に 1 ぀の倉曎が必芁です。

これで、このアプリは以前ず同様に正垞に機胜し、認蚌されたすが、ペヌゞを衚瀺する前にリダむレクトされたす。リンクを衚瀺するには、WebSecurityConfigurerAdapter を継承しおホヌムペヌゞのセキュリティをオフにする必芁もありたす。

SocialApplication
@SpringBootApplication
@RestController
public class SocialApplication extends WebSecurityConfigurerAdapter {

    // ...

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    	// @formatter:off
        http
            .authorizeRequests(a -> a
                .antMatchers("/", "/error", "/webjars/**").permitAll()
                .anyRequest().authenticated()
            )
            .exceptionHandling(e -> e
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
            )
            .oauth2Login();
        // @formatter:on
    }

}

Spring Boot は、@SpringBootApplication アノテヌションが付けられたクラスの WebSecurityConfigurerAdapter ã«ç‰¹åˆ¥ãªæ„å‘³ã‚’付加したす。これを䜿甚しお、OAuth 2.0 認蚌プロセッサヌを運ぶセキュリティフィルタヌチェヌンを構成したす。

䞊蚘の構成は、蚱可された゚ンドポむントのホワむトリストを瀺し、他のすべおの゚ンドポむントは認蚌を必芁ずしたす。

蚱可したい:

  • /。これは動的に䜜成したペヌゞであり、そのコンテンツの䞀郚は認蚌されおいないナヌザヌにも衚瀺されるためです。

  • /error。これは、゚ラヌを衚瀺するための Spring Boot ゚ンドポむント

  • /webjars/** ã¯ã€èªèšŒã•れおいるかどうかにかかわらず、すべおの蚪問者に察しお JavaScript を実行するためです。

ただし、この構成では /user ã«ã€ã„おは䜕も衚瀺されたせん。/user ã‚’含むすべおのものは、最埌の .anyRequest().authenticated() æ§‹æˆã®ãŸã‚ã«ç€ºã•れない限り、安党なたたです。

最埌に、Ajax を介しおバック゚ンドずむンタヌフェヌスするため、ログむンペヌゞにリダむレクトするデフォルトの動䜜ではなく、401 で応答するように゚ンドポむントを構成する必芁がありたす。authenticationEntryPoint ã‚’構成するこずでこれが実珟したす。

これらの倉曎が完了するず、アプリケヌションが完成したす。アプリケヌションを実行しおホヌムペヌゞにアクセスするず、「GitHub でログむン」ぞの適切なスタむルの HTML リンクが衚瀺されたす。このリンクは、GitHub に盎接ではなく、認蚌を凊理するおよび GitHub にリダむレクトを送信するロヌカルパスに移動したす。認蚌が完了するず、ロヌカルアプリにリダむレクトされ、名前が衚瀺されるようになりたすGitHub でそのデヌタぞのアクセスを蚱可するようにアクセス蚱可を蚭定した堎合。

ログアりトボタンを远加する

このセクションでは、ナヌザヌがアプリからログアりトできるボタンを远加しお、䜜成したクリックアプリを倉曎したす。これは単玔な機胜のように芋えたすが、実装には倚少の泚意が必芁なので、正確に行う方法を議論するのに時間をかける䟡倀がありたす。ほずんどの倉曎は、アプリを読み取り専甚リ゜ヌスから読み取り / 曞き蟌みリ゜ヌスに倉換しおいるずいう事実に関係しおいるためログアりトには状態の倉曎が必芁です、実際のアプリケヌションでは同じ倉曎が必芁になりたす。単なる静的コンテンツではありたせん。

クラむアント偎の倉曎

クラむアントでは、ログアりトボタンずいく぀かの JavaScript を提䟛するだけで、サヌバヌにコヌルバックしお認蚌のキャンセルを芁求できたす。たず、UI の「認蚌枈み」セクションで、ボタンを远加したす。

index.html
<div class="container authenticated">
  Logged in as: <span id="user"></span>
  <div>
    <button onClick="logout()" class="btn btn-primary">Logout</button>
  </div>
</div>

そしお、JavaScript で参照する logout() é–¢æ•°ã‚’提䟛したす。

index.html
var logout = function() {
    $.post("/logout", function() {
        $("#user").html('');
        $(".unauthenticated").show();
        $(".authenticated").hide();
    })
    return true;
}

logout() é–¢æ•°ã¯ /logout ã«å¯Ÿã—お POST を実行し、動的コンテンツをクリアしたす。これで、サヌバヌ偎に切り替えおその゚ンドポむントを実装できたす。

ログアりト゚ンドポむントの远加

Spring Security は、/logout ã‚šãƒ³ãƒ‰ãƒã‚€ãƒ³ãƒˆã®ã‚µãƒãƒŒãƒˆã‚’組み蟌んでいたす。これにより、正しい凊理が行われたすセッションをクリアし、Cookie を無効にしたす。゚ンドポむントを構成するには、WebSecurityConfigurerAdapter の既存の configure() ãƒ¡ã‚œãƒƒãƒ‰ã‚’単玔に拡匵したす。

SocialApplication.java
@Override
protected void configure(HttpSecurity http) throws Exception {
	// @formatter:off
    http
        // ... existing code here
        .logout(l -> l
            .logoutSuccessUrl("/").permitAll()
        )
        // ... existing code here
    // @formatter:on
}

/logout ã‚šãƒ³ãƒ‰ãƒã‚€ãƒ³ãƒˆã¯ã€POST する必芁があり、ナヌザヌをクロスサむトリク゚ストフォヌゞェリCSRF、「シヌサヌフ」ず発音から保護するには、トヌクンをリク゚ストに含める必芁がありたす。トヌクンの倀は珟圚のセッションにリンクされおおり、これが保護を提䟛しおいるため、JavaScript アプリにそのデヌタを取埗する方法が必芁です。

倚くの JavaScript フレヌムワヌクには CSRF のサポヌトが組み蟌たれおいたすが (たずえば、Angular では XSRF ず呌ばれおいたす)、倚くの堎合、Spring Security の暙準の動䜜ずは少し異なる方法で実装されおいたす。たずえば、Angular では、フロント゚ンドはサヌバヌから "XSRF-TOKEN" ずいう Cookie が送信されるこずを望んでおり、それを怜出するず、その倀を "X-XSRF-TOKEN" ずいうヘッダヌずしお返したす。同じ動䜜をシンプルな jQuery クラむアントで実装するず、サヌバヌ偎の倉曎は、倉曎をたったく行わず、たたはほずんど行わずに他のフロント゚ンド実装でも機胜したす。Spring Security にこれを教えるには、Cookie を䜜成するフィルタヌを远加する必芁がありたす。

WebSecurityConfigurerAdapter ã§ã¯ã€æ¬¡ã®ã“ずを行いたす。

SocialApplication.java
@Override
protected void configure(HttpSecurity http) throws Exception {
	// @formatter:off
    http
        // ... existing code here
        .csrf(c -> c
            .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
        )
        // ... existing code here
    // @formatter:on
}

クラむアントに CSRF トヌクンを远加する

このサンプルでは高レベルのフレヌムワヌクを䜿甚しおいないため、バック゚ンドから Cookie ずしお䜿甚可胜にした CSRF トヌクンを明瀺的に远加する必芁がありたす。コヌドを少し単玔にするために、js-cookie ãƒ©ã‚€ãƒ–ラリをむンクルヌドしたす。

pom.xml
<dependency>
    <groupId>org.webjars</groupId>
    <artifactId>js-cookie</artifactId>
    <version>2.1.0</version>
</dependency>

次に、HTML で参照できたす。

index.html
<script type="text/javascript" src="/webjars/js-cookie/js.cookie.js"></script>

最埌に、XHR で Cookies ã‚³ãƒ³ãƒ“ニ゚ンスメ゜ッドを䜿甚できたす。

index.html
$.ajaxSetup({
  beforeSend : function(xhr, settings) {
    if (settings.type == 'POST' || settings.type == 'PUT'
        || settings.type == 'DELETE') {
      if (!(/^http:.*/.test(settings.url) || /^https:.*/
        .test(settings.url))) {
        // Only send the token to relative URLs i.e. locally.
        xhr.setRequestHeader("X-XSRF-TOKEN",
          Cookies.get('XSRF-TOKEN'));
      }
    }
  }
});

準備完了 !

これらの倉曎が完了したら、アプリを実行しお新しいログアりトボタンを詊す準備ができたした。アプリを起動し、新しいブラりザヌりィンドりにホヌムペヌゞを読み蟌みたす。「ログむン」リンクをクリックしお、GitHub に移動したすすでにログむンしおいる堎合は、リダむレクトに気付かない堎合がありたす。ログアりトボタンをクリックしお、珟圚のセッションをキャンセルし、アプリを認蚌されおいない状態に戻したす。興味がある堎合は、ブラりザヌがロヌカルサヌバヌず亀換するリク゚ストで新しい Cookie ずヘッダヌを確認できるはずです。

ログアりト゚ンドポむントがブラりザヌクラむアントで動䜜するようになりたした。他のすべおの HTTP リク゚ストPOST、PUT、DELETE なども同様に動䜜するこずを芚えおおいおください。これは、より珟実的な機胜を備えたアプリケヌションに適したプラットフォヌムになるはずです。

GitHub でログむン

このセクションでは、すでに構築したログアりトアプリを倉曎し、ステッカヌペヌゞを远加しお、゚ンドナヌザヌが耇数の資栌情報セットから遞択できるようにしたす。

゚ンドナヌザヌの 2 番目のオプションずしお Google を远加したしょう。

初期蚭定

ログむンに Google の OAuth 2.0 認蚌システムを䜿甚するには、Google API コン゜ヌルでプロゞェクトを蚭定し、OAuth 2.0 資栌情報を取埗する必芁がありたす。

認蚌甚の Google の OAuth 2.0 実装 (英語) は OpenID Connect 1.0 (英語) 仕様に準拠しおおり、OpenID 認定 (英語) です。

「OAuth 2.0 のセットアップ」セクションから始たる OpenID Connect (英語) ペヌゞの指瀺に埓っおください。

「OAuth 2.0 資栌情報の取埗」の手順を完了するず、クラむアント ID ずクラむアントシヌクレットで構成される資栌情報を持぀新しい OAuth クラむアントが必芁になりたす。

リダむレクト URI の蚭定

たた、以前に GitHub に察しお行ったように、リダむレクト URI を提䟛する必芁がありたす。

「リダむレクト URI の蚭定」サブセクションで、承認されたリダむレクト URI フィヌルドが http://localhost:8080/login/oauth2/code/google に蚭定されおいるこずを確認したす。

クラむアント登録の远加

次に、Google を指すようにクラむアントを構成する必芁がありたす。Spring Security は耇数のクラむアントを念頭に眮いお構築されおいるため、GitHub 甚に䜜成した資栌情報ず䞊行しお Google 資栌情報を远加できたす。

application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          github:
            clientId: github-client-id
            clientSecret: github-client-secret
          google:
            client-id: google-client-id
            client-secret: google-client-secret

ご芧のずおり、Google は、Spring Security がすぐに䜿甚できるサポヌトを提䟛するもう 1 ぀のプロバむダヌです。

クラむアントでは、倉曎は簡単です - 別のリンクを远加するだけです:

index.html
<div class="container unauthenticated">
  <div>
    With GitHub: <a href="/oauth2/authorization/github">click here</a>
  </div>
  <div>
    With Google: <a href="/oauth2/authorization/google">click here</a>
  </div>
</div>
URL の最終パスは、application.yml のクラむアント登録 ID ず䞀臎する必芁がありたす。
Spring Security には、/oauth2/authorization/{registrationId} ではなく /login ã‚’ポむントするこずでアクセスできるデフォルトのプロバむダヌ遞択ペヌゞが付属しおいたす。

ロヌカルナヌザヌデヌタベヌスを远加する方法

倚くのアプリケヌションは、認蚌が倖郚プロバむダヌに委譲されおいる堎合でも、ナヌザヌに関するデヌタをロヌカルに保持する必芁がありたす。ここではコヌドを瀺しおいたせんが、2 ぀のステップで簡単に実行できたす。

  1. デヌタベヌスのバック゚ンドを遞択し、ニヌズに合ったカスタム User ã‚ªãƒ–ゞェクトのリポゞトリたずえば Spring Data を䜿甚をセットアップし、倖郚認蚌から完党たたは郚分的にデヌタを取り蟌むこずができたす。

  2. OAuth2UserService ã‚’実装しお公開し、デヌタベヌスず同様に認可サヌバヌを呌び出したす。実装はデフォルトの実装に委譲できたす。これにより、認可サヌバヌを呌び出すずいう手間がかかりたす。実装は、カスタム User ã‚ªãƒ–ゞェクトを継承し、OAuth2User を実装するものを返す必芁がありたす。

ヒント: User ã‚ªãƒ–ゞェクトにフィヌルドを远加しお、倖郚プロバむダヌの䞀意の識別子にリンクしたすナヌザヌの名前ではなく、倖郚プロバむダヌのアカりントに固有のもの。

認蚌されおいないナヌザヌ甚の゚ラヌペヌゞの远加

このセクションでは、以前に䜜成した 2 ぀のプロバむダヌアプリを倉曎しお、認蚌できないナヌザヌにフィヌドバックを提䟛したす。同時に、認蚌ロゞックを継承しお、ナヌザヌが特定の GitHub 組織に属しおいる堎合にのみナヌザヌを蚱可するルヌルを含めたす。「組織」は GitHub ドメむン固有の抂念ですが、同様のルヌルが他のプロバむダヌにも考案される可胜性がありたす。䟋: Google では、特定のドメむンのナヌザヌのみを認蚌したい堎合がありたす。

GitHub ぞの切り替え

2 プロバむダヌのサンプルでは、GitHub を OAuth 2.0 プロバむダヌずしお䜿甚しおいたす。

application.yml
spring:
  security:
    oauth2:
      client:
        registration:
          github:
            client-id: bd1c0a783ccdd1c9b9e4
            client-secret: 1a9030fbca47a5b2c28e92f19050bb77824b5ad1
          # ...

クラむアントでの認蚌倱敗の怜出

クラむアントでは、認蚌できなかったナヌザヌにフィヌドバックを提䟛するこずができたす。これを容易にするために、最終的に情報メッセヌゞを远加する div を远加できたす。

index.html
<div class="container text-danger error"></div>

次に、/error ã‚šãƒ³ãƒ‰ãƒã‚€ãƒ³ãƒˆã«å‘Œã³å‡ºã—を远加し、<div> ã«çµæžœã‚’入力したす。

index.html
$.get("/error", function(data) {
    if (data) {
        $(".error").html(data);
    } else {
        $(".error").html('');
    }
});

゚ラヌ関数は、衚瀺する゚ラヌがあるかどうかをバック゚ンドで確認したす

゚ラヌメッセヌゞを远加する

゚ラヌメッセヌゞの取埗をサポヌトするには、認蚌が倱敗したずきにキャプチャヌする必芁がありたす。これを実珟するために、次のように AuthenticationFailureHandler を構成できたす。

protected void configure(HttpSecurity http) throws Exception {
	// @formatter:off
	http
	    // ... existing configuration
	    .oauth2Login(o -> o
            .failureHandler((request, response, exception) -> {
			    request.getSession().setAttribute("error.message", exception.getMessage());
			    handler.onAuthenticationFailure(request, response, exception);
            })
        );
}

䞊蚘は、認蚌が倱敗するたびに゚ラヌメッセヌゞをセッションに保存したす。

次に、次のような単玔な /error ã‚³ãƒ³ãƒˆãƒ­ãƒŒãƒ©ãƒŒã‚’远加できたす。

SocialApplication.java
@GetMapping("/error")
public String error(HttpServletRequest request) {
	String message = (String) request.getSession().getAttribute("error.message");
	request.getSession().removeAttribute("error.message");
	return message;
}
これにより、アプリのデフォルトの /error ãƒšãƒŒã‚žãŒçœ®ãæ›ãˆã‚‰ã‚ŒãŸã™ã€‚これは、このケヌスでは問題ありたせんが、ニヌズに合わせお十分に掗緎されおいない堎合がありたす。

サヌバヌで 401 を生成する

ナヌザヌが GitHub でログむンできない、たたはログむンしたくない堎合は、Spring Security から 401 レスポンスがすでに送信されるため、認蚌に倱敗した堎合トヌクンの付䞎を拒吊するなど、アプリはすでに動䜜しおいたす。

少し物事を盛り䞊げるために、適切な組織にいないナヌザヌを拒吊するように認蚌ルヌルを継承できたす。

GitHub API を䜿甚しおナヌザヌの詳现を調べるこずができるため、認蚌プロセスの適切な郚分にプラグむンするだけです。

幞い、Spring Boot はそのような単玔な䜿甚䟋のために、簡単な拡匵ポむントを提䟛しおいたす。型 OAuth2UserService の @Bean ã‚’宣蚀するず、ナヌザヌプリンシパルを識別するために䜿甚されたす。そのフックを䜿甚しお、ナヌザヌが正しい組織にいるこずをアサヌトし、そうでない堎合は䟋倖をスロヌできたす。

SocialApplication.java
@Bean
public OAuth2UserService<OAuth2UserRequest, OAuth2User> oauth2UserService(WebClient rest) {
    DefaultOAuth2UserService delegate = new DefaultOAuth2UserService();
    return request -> {
        OAuth2User user = delegate.loadUser(request);
        if (!"github".equals(request.getClientRegistration().getRegistrationId())) {
        	return user;
        }

        OAuth2AuthorizedClient client = new OAuth2AuthorizedClient
                (request.getClientRegistration(), user.getName(), request.getAccessToken());
        String url = user.getAttribute("organizations_url");
        List<Map<String, Object>> orgs = rest
                .get().uri(url)
                .attributes(oauth2AuthorizedClient(client))
                .retrieve()
                .bodyToMono(List.class)
                .block();

        if (orgs.stream().anyMatch(org -> "spring-projects".equals(org.get("login")))) {
            return user;
        }

        throw new OAuth2AuthenticationException(new OAuth2Error("invalid_token", "Not in Spring Team", ""));
    };
}

このコヌドは、認蚌されたナヌザヌに代わっお GitHub API にアクセスするための WebClient ã‚€ãƒ³ã‚¹ã‚¿ãƒ³ã‚¹ã«äŸå­˜ã—おいるこずに泚意しおください。それが完了するず、組織をルヌプしお、"spring-projects" これは Spring オヌプン゜ヌスプロゞェクトを栌玍するために䜿甚される組織に䞀臎する組織を探したす。正垞に認蚌できるようにしたいが、Spring ゚ンゞニアリングチヌムに所属しおいない堎合は、そこで独自の倀に眮き換えるこずができたす。䞀臎するものがない堎合は、OAuth2AuthenticationException がスロヌされ、これが Spring Security によっお取埗され、401 レスポンスになりたす。

WebClient ã‚‚ Bean ずしお䜜成する必芁がありたすが、spring-boot-starter-oauth2-client を䜿甚したこずでその成分がすべお自動で曞き蟌めるため、簡単です。

@Bean
public WebClient rest(ClientRegistrationRepository clients, OAuth2AuthorizedClientRepository authz) {
    ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2 =
            new ServletOAuth2AuthorizedClientExchangeFilterFunction(clients, authz);
    return WebClient.builder()
            .filter(oauth2).build();
}
明らかに、䞊蚘のコヌドは他の認蚌ルヌルに䞀般化でき、䞀郚は GitHub に、䞀郚は他の OAuth 2.0 プロバむダヌに適甚できたす。必芁なのは、WebClient ãšãƒ—ロバむダヌの API の知識だけです。

結論

Spring Boot ず Spring Security を䜿甚しお、非垞に少ない劎力で倚くのスタむルのアプリを構築する方法を芋おきたした。すべおのサンプルで実行されるメむンテヌマは、倖郚 OAuth 2.0 プロバむダヌを䜿甚した認蚌です。

サンプルアプリケヌションはすべお、通垞は構成ファむルを倉曎するだけで、より具䜓的なナヌスケヌスに合わせお簡単に拡匵および再構成できたす。独自のサヌバヌでサンプルのバヌゞョンを䜿甚しお GitHubたたは同様のに登録し、独自のホストアドレスのクラむアント資栌情報を取埗する堎合は芚えおおいおください。そしお、それらの資栌情報を゜ヌス管理に入れないこずを忘れないでください

新しいガむドを䜜成したり、既存のガむドに貢献したいですか 投皿ガむドラむンを参照しおください [GitHub] (英語) 。

すべおのガむドは、コヌド甚の ASLv2 ラむセンス、およびドキュメント甚の Attribution、NoDerivatives creative commons ラむセンス (英語) でリリヌスされおいたす。

コヌドを入手する