Upgrade to Pro — share decks privately, control downloads, hide ads and more …

OAuth 2.0 with Spring Security #jjug_ccc #jjug_ccc_b / oauth2-with-spring-security

Masatoshi Tada
November 07, 2020

OAuth 2.0 with Spring Security #jjug_ccc #jjug_ccc_b / oauth2-with-spring-security

JJUG CCC 2020 Fallでの講演資料です。Spring SecurityのOAuth 2.0機能について解説しています。OAuth 2.0自体は理解している前提の、中級者向け資料です。

Masatoshi Tada

November 07, 2020
Tweet

More Decks by Masatoshi Tada

Other Decks in Technology

Transcript

  1. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUI
    XJUI
    4QSJOH4FDVSJUZ
    ג
    ΧαϨΞϧଟాਅහ
    ೥݄೔
    ++6($$$'BMM

    View Slide

  2. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ͜ͷηογϣϯʹ͍ͭͯ
    ▸ 4QSJOH4FDVSJUZͷ0"VUIؔ࿈ػೳΛɺ
    ࢓૊Έ΋ؚΊͯ෼͔Γ΍͘͢ղઆ͠·͢
    ▸ αϯϓϧίʔυ
    ▸ IUUQTHJUIVCDPN.BTBUPTIJ5BEBPBVUIXJUI
    TQSJOHTFDVSJUZ

    View Slide

  3. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ඞཁͳલఏ஌ࣝ
    ▸ ͜ͷηογϣϯ͸ʲதڃऀ޲͚ʳͰ͢
    ▸ ҎԼͷલఏ஌͕ࣝඞཁͰ͢
    ▸ "VUIPSJ[BUJPO$PEF(SBOU'MPXΛઆ໌Ͱ͖Δ
    ▸ 4QSJOH4FDVSJUZΛ࢖ͬͨ͜ͱ͕͋Δ
    ▸ 0"VUIػೳͰͳͯ͘΋0,

    View Slide

  4. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ઌʹ݁࿦
    ▸ 4QSJOH4FDVSJUZ಺෦ͷRestTemplateʹ͸ɺ
    λΠϜΞ΢τ͕ઃఆ͞Ε͍ͯͳ͍͜ͱ͕
    ΄ͱΜͲ
    ˠͪΌΜͱλΠϜΞ΢τΛઃఆ͠·͠ΐ͏

    View Slide

  5. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUIͷجૅΛ஌Γ͍ͨํ͸ʜ

    https://www.slideshare.net/masatoshitada7/oauth-20spring-security-51-121418814

    View Slide

  6. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOH4FDVSJUZͷΞʔΩςΫνϟΛ஌Γ͍ͨํ͸ʜ

    https://www.slideshare.net/masatoshitada7/spring-security-meetup

    View Slide

  7. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ࣗݾ঺հ
    ▸ ଟాਅහʢ[email protected]ʣ
    ▸ ݚमτϨʔφʔ!ΧαϨΞϧ
    ▸ +BWB(PMBOH.JDSPTFSWJDFT
    ,VCFSOFUFT1ZUIPOػցֶश
    ▸ 7.XBSFೝఆߨࢣ
    ▸ ೔ຊ4QSJOHϢʔβձελοϑ

    View Slide

  8. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ઌʹ͓࿳ͼ͓͖ͯ͠·͢
    ▸ ່ࢯʢϲ݄ʣͷ੠͕ͱ͜ΖͲ͜ΖೖΔ͔΋
    ͠Ε·ͤΜ

    View Slide

  9. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    גࣜձࣾΧαϨΞϧ
    ▸ ଞࣾʹ͸ແ͍৭ʑͳϓϩάϥϛϯάݴޠͷ
    ݚमΛఏڙ͍ͯ͠·͢ʂ

    /&8

    View Slide

  10. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOHܥίʔε

    ▸ جૅ͔Βͷ4QSJOH#PPUʹΑΔ
    8FCΞϓϦέʔγϣϯ։ൃʢ೔ؒʣ
    ▸ 7.XBSF5BO[Vೝఆ4QSJOH$PSF5SBJOJOHʢ೔ؒʣ
    ▸ 7.XBSF5BO[Vೝఆ4QSJOH$MPVE%FWFMPQFSʢ೔ؒʣ
    ▸ جૅ͔Βͷ4QSJOH4FDVSJUZʢ೔ؒʣ
    ▸ جૅ͔Βͷ4QSJOH#BUDIʢ೔ؒʣ

    View Slide

  11. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ৽نίʔεϦϦʔε

    (PݴޠʹΑΔ
    Ϋϥ΢υωΠςΟϒΞϓϦέʔγϣϯ։ൃ
    جຊจ๏ɺ8FCΞϓϦέʔγϣϯɺϚΠΫϩαʔϏε
    1ZUIPOೖ໳
    جຊจ๏ɺϥΠϒϥϦͷར༻ɺ8FCεΫϨΠϐϯά
    1ZUIPOʹΑΔػցֶशೖ໳ʢԾʣ

    View Slide

  12. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΦϯϥΠϯݚमɺ͸͡Ί·ͨ͠

    ߨࢣ
    डߨऀ༷
    ▸ ʮֶशޮՌ͸௨ৗͱมΘΒͳ͍ʯ
    ͱ޷ධͰ͢ʂ

    View Slide

  13. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  14. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  15. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUIͱ͸
    ▸ ೝՄͷྲྀΕΛنఆͨ͠ϓϩτίϧ
    ▸ 3'$ ೔ຊޠ൛΋͋Δ

    ▸ 0"VUIͱ͸ผ෺
    ▸ 4USVUTͱ4USVUT͘Β͍ҧ͏
    ▸ ೝূϓϩτίϧ0QFO*%$POOFDU
    ͷϕʔεʹͳ͍ͬͯΔ

    View Slide

  16. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUIͷొ৔ਓ෺
    ᶃ ϦιʔεΦʔφʔ 3FTPVSDF0XOFS

    ▸ ৘ใͷ࣋ͪओɻଟ͘ͷέʔεͰ͸ਓؒɻ
    ᶄ Ϧιʔεαʔόʔ 3FTPVSDF4FSWFS

    ▸ ৘ใΛอ࣋͢Δαʔόʔɻ
    ᶅ ΫϥΠΞϯτ $MJFOU

    ▸ Ϧιʔεαʔόʔ͔Β΋Βͬͨ৘ใΛѻ͏ΞϓϦέʔγϣϯɻ
    ᶆ ೝՄαʔόʔ "VUIPSJ[BUJPO4FSWFS

    ▸ ΞΫηετʔΫϯΛൃߦ͢Δαʔόʔɻ

    View Slide

  17. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    5XJUUFSͷྫͰొ৔ਓ෺·ͱΊ

    twitter.com
    ͜Μʹͪ͸!

    ָ͠Έͩͳʔ
    Ϧιʔε

    Φʔφʔ
    ΫϥΠΞϯτ
    Ϧιʔεαʔόʔ
    ೝՄαʔόʔ
    ೝՄ
    ΞΫηε

    τʔΫϯ

    ෇༩
    ΞΫηε

    τʔΫϯ
    ͭͿ΍͖
    ※ຊ౰͸Twitter͸OAuth 1.0Λ࢖͍ͬͯ·͢

    View Slide

  18. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    άϥϯτλΠϓʢΞΫηετʔΫϯͷऔಘํ๏ʣ
    ᶃ ೝՄίʔυ
    ▸ ओʹαʔόʔαΠυ8FCΞϓϦέʔγϣϯ
    ᶄ ΠϯϓϦγοτʢඇਪ঑ʣ
    ▸ ओʹΫϥΠΞϯταΠυ8FCΞϓϦέʔγϣϯ
    ᶅ ϦιʔεΦʔφʔύεϫʔυΫϨσϯγϟϧʢඇਪ঑ʣ
    ▸ ओʹެࣜͷεϚϗΞϓϦͳͲ
    ᶆ ΫϥΠΞϯτΫϨσϯγϟϧ
    ▸ ΫϥΠΞϯτࣗ਎ͷ৘ใऔಘ

    View Slide

  19. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    <ࢀߟ>0"VUIͷ࢓༷ࡦఆ͕ਐߦத
    ▸ 0"VUIͷ࢓༷ʴͦͷଞΛ࠶੔ཧͨ͠΋ͷ
    ˠطʹඇਪ঑ͱͳ͍ͬͯΔػೳ͕࡟আ͞ΕΔ
    ▸ ΠϯϓϦγοτ
    ▸ ϦιʔεΦʔφʔύεϫʔυΫϨσϯγϟϧ
    ▸ ৄࡉ͸ͪ͜Βͷهࣄ΁
    ▸ 0"VUIͷඪ४Խ͕ਐΊΒΕ͍ͯ·͢
    [email protected]
    ▸ 4QSJOH4FDVSJUZͷ0"VUIରԠ༧ఆ͸ɺݱ࣌఺Ͱ͸ෆ໌

    View Slide

  20. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε

    View Slide

  21. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ

    View Slide

  22. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
    ᶅೝՄը໘

    View Slide

  23. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
    ᶅೝՄը໘
    ᶆೝՄ

    View Slide

  24. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶇೝՄίʔυൃߦʴϦμΠϨΫτ
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
    ᶅೝՄը໘
    ᶆೝՄ

    View Slide

  25. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶇೝՄίʔυൃߦʴϦμΠϨΫτ
    ᶈೝՄίʔυ
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
    ᶅೝՄը໘
    ᶆೝՄ

    View Slide

  26. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β※
    ※Webϒϥ΢β͸ɺ࢓༷ॻͰ͸ʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢
    ᶃॳճΞΫηε
    ᶇೝՄίʔυൃߦʴϦμΠϨΫτ
    ᶈೝՄίʔυ
    ᶉΞΫηετʔΫϯ
    ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
    ᶅೝՄը໘
    ᶆೝՄ

    View Slide

  27. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ

    View Slide

  28. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  29. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶅΞΫηε

    ɹτʔΫϯ

    ɹݕূ
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  30. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶅΞΫηε

    ɹτʔΫϯ

    ɹݕূ
    ᶆݕূ݁ՌΛฦ͢
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  31. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶅΞΫηε

    ɹτʔΫϯ

    ɹݕূ
    ᶆݕূ݁ՌΛฦ͢
    ᶇݕূ݁ՌΛ

    ɹ֬ೝ
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  32. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶅΞΫηε

    ɹτʔΫϯ

    ɹݕূ
    ᶆݕূ݁ՌΛฦ͢
    ᶈϨεϙϯε
    ᶇݕূ݁ՌΛ

    ɹ֬ೝ
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  33. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε

    ೝՄαʔόʔ
    ΫϥΠΞϯτ
    Ϧιʔε

    Φʔφʔ
    Web

    ϒϥ΢β
    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε

    αʔόʔ
    ᶃϦΫΤετ
    ᶅΞΫηε

    ɹτʔΫϯ

    ɹݕূ
    ᶆݕূ݁ՌΛฦ͢
    ᶈϨεϙϯε
    ᶉϨεϙϯε
    ᶇݕূ݁ՌΛ

    ɹ֬ೝ
    ᶄϦιʔεʹΞΫηε

    with ΞΫηετʔΫϯ

    View Slide

  34. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  35. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ґଘੑ


    org.springframework.boot

    spring-boot-starter-oauth2-client


    wTQSJOHTFDVSJUZDPOpH
    wTQSJOHTFDVSJUZPBVUIDMJFOU
    ͳͲؚ͕·Ε͍ͯΔ

    View Slide

  36. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    BQQMJDBUJPOZNM

    spring.security.oauth2.client.registration.todo:
    provider: ೚ҙͷ໊લ(.registrationͷޙʹ΋ࢦఆ͢Δ)
    client-id: ΫϥΠΞϯτID
    client-secret: ΫϥΠΞϯτγʔΫϨοτ
    client-name: ೚ҙͷ໊લ(ը໘දࣔͰ࢖ΘΕΔ)
    client-authentication-method: ΫϥΠΞϯτೝূํ๏
    authorization-grant-type: άϥϯτλΠϓ
    redirect-uri: ϦμΠϨΫτΤϯυϙΠϯτͷURL
    scope: ͜ͷΞϓϦͷείʔϓΛΧϯϚ۠੾ΓͰࢦఆ
    ※εϖʔεͷ౎߹্ͰYAMLܗࣜͰॻ͍͍ͯ·͕͢ɺݸਓతʹ͸properties೿Ͱ͢

    View Slide

  37. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    BQQMJDBUJPOZNMʢଓ͖ʣ

    spring.security.oauth2.client.provider.todo:
    authorization-uri: ೝՄΤϯυϙΠϯτͷURL
    token-uri: τʔΫϯΤϯυϙΠϯτͷURL
    user-info-uri: Ϣʔβʔ৘ใͷJSON͕ฦͬͯ͘ΔURL
    user-name-attribute: JSONͷதͷϢʔβʔ໊Λද͢ଐੑ໊
    user-info-authentication-method: Ϣʔβʔ৘ใऔಘ࣌ͷೝূํࣜ
    jwk-set-uri: JWK Set͕ฦͬͯ͘ΔURL
    issuer-uri: ೝՄαʔόʔͷIssuer Identifier
    ※Keycloakͷ৔߹ɺissuer-uriΛࢦఆ͢Ε͹ଞͷϓϩύςΟ͸ࢦఆෆཁʢuser-name-attribute͸೚ҙʣ

    View Slide

  38. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +BWB$POpH

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.oauth2Login()
    .loginPage("/login")
    .permitAll();
    ...
    }
    }
    ϩάΠϯʹؔ͢Δઃఆ

    View Slide

  39. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOH4FDVSJUZ'JMUFS$IBJO

    SecurityContextPersistenceFilter
    LogoutFilter
    OAuth2AuthorizationRequestRedirectFilter
    OAuth2LoginAuthenticationFilter
    ExceptionTranslationFilter
    FilterSecurityInterceptor
    ϦΫΤετ
    ೝՄΤϯυϙΠϯτʹ
    ϦμΠϨΫτ͢Δ
    ೝূΛߦ͏

    View Slide

  40. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUI"VUIPSJ[BUJPO3FRVFTU3FEJSFDU'JMUFS
    ▸ ೝՄ͕ඞཁͳ৔߹ɺೝՄαʔόʔͷ
    ೝՄΤϯυϙΠϯτʹϦμΠϨΫτ͍ͯ͠Δ

    @Override
    protected void doFilterInternal(HttpServletRequest request,
    HttpServletResponse response, FilterChain filterChain)
    throws ServletException, IOException {
    try {
    OAuth2AuthorizationRequest authorizationRequest =
    this.authorizationRequestResolver.resolve(request);
    if (authorizationRequest != null) {
    this.sendRedirectForAuthorization(
    request, response, authorizationRequest);
    return;
    }
    ...
    https://github.com/spring-projects/spring-security/blob/master/oauth2/
    oauth2-client/src/main/java/org/springframework/security/oauth2/
    client/web/OAuth2AuthorizationRequestRedirectFilter.java#L164

    View Slide

  41. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUI-PHJO"VUIFOUJDBUJPO'JMUFS಺Ͱͷॲཧ

    OAuth2LoginAuthenticationFilter
    ProviderManager
    OidcAuthorizationCodeAuthenticationProvider
    DefaultAuthoriaztionCodeTokenResponseClient
    ᶃೝՄίʔυΛड͚औΔ
    ᶄೝՄίʔυΛ࣋ͬͨ
    ɹAuthenticationΛ౉͢
    ᶅೝՄίʔυΛ࣋ͬͨ
    ɹAuthenticationΛ౉͢
    ᶆݺͼग़͠
    ᶇOAuth2AccessToken
    ɹResponseΛฦ͢
    ᶈ+85͔Β"VUIPSJUZΛநग़ɹ
    ɹˠAuthenticationΛฦ͢
    ᶉAuthenticationΛฦ͢
    ᶊSecurityContextʹɹ
    ɹAuthenticationΛอଘ

    View Slide

  42. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    %FGBVMU"VUIPSJ[BUJPO$PEF5PLFO3FTQPOTF$MJFOU
    ▸ RestTemplateͰೝՄαʔόʔʹ
    ΞΫηεͯ͠ɺΞΫηετʔΫϯͷऔಘΛߦ͏
    ▸ ͜ͷRestTemplateʹ͸ɺσϑΥϧτͰ͸
    λΠϜΞ΢τ͕ઃఆ͞Ε͍ͯͳ͍

    View Slide

  43. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +BWB$POpHʹઃఆΛ௥Ճ

    private DefaultAuthorizationCodeTokenResponseClient client() {
    RestTemplate restTemplate = restTemplateBuilder
    // λΠϜΞ΢τΛઃఆ
    .setConnectTimeout(Duration.ofMillis(1000))
    .setReadTimeout(Duration.ofMillis(1000))
    ...
    .build();
    DefaultAuthorizationCodeTokenResponseClient client =
    new DefaultAuthorizationCodeTokenResponseClient();
    // λΠϜΞ΢τઃఆࡁΈͷRestTemplateΛઃఆ
    client.setRestOperations(restTemplate);
    return client;
    }

    View Slide

  44. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +BWB$POpHͷઃఆΛมߋ

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.oauth2Login(oauth2 -> oauth2
    // λΠϜΞ΢τઃఆࡁΈͷTokenResponseClientΛࢦఆ
    .tokenEndpoint(token -> token
    .accessTokenResponseClient(client())
    )
    ...
    .loginPage("/login")
    .permitAll()
    ).authorizeRequests(auth -> auth
    ...
    ˞εϥΠυͰ͸εϖʔεͷ౎߹্ׂѪ͍ͯ͠·͕͢ɺOAuth2UserService΍
    ɹOidcUserServiceʹ΋ಉ༷ͷઃఆ͕ඞཁͰ͢ʢৄࡉ͸(JU)VCࢀরʣ

    View Slide

  45. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  46. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    8FC$MJFOUͱ͸ʁ
    ▸ 4QSJOH8FC'MVYʹؚ·Ε͍ͯΔɺ
    ϦΞΫςΟϒͳ)551ΫϥΠΞϯτ
    ▸ 3FBDUPSͷ'MVY.POPΛ׆༻
    ▸ ྲྀΕΔΑ͏ͳ"1*

    public List findAll() {
    return webClient.get()
    .uri("/todos")
    .retrieve()
    .bodyToFlux(Todo.class)
    .collectList()
    .block();
    }

    View Slide

  47. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    3FTU5FNQMBUFͷ+BWBEPDΑΓ

    https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/web/client/
    RestTemplate.html
    ɾҎ߱Ͱ͸ϝϯςφϯεϞʔυ΍Ͱ
    ɾ୅ΘΓʹ8FC$MJFOUͷར༻Λݕ౼ͯ͠΍

    View Slide

  48. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    8FC$MJFOUʹҠߦ͢΂͖͔ʁ
    ▸ ·ͩ࢑͘͸3FTU5FNQMBUFͰΑ͍ ଟాݸਓͷҙݟ

    ▸ ΞϓϦέʔγϣϯ΍4QSJOHຊମͳͲ΁ͷӨڹ͕ඇৗʹେ͖͍
    ͨΊɺ3FTU5FNQMBUF͕͙͢ʹ࡟আ͞ΕΔͱ͸ࢥ͑ͳ͍
    ▸ 8FC$MJFOUΛ࢖͏ͱɺͲ͏ͯ͠΋'MVY.POPΛ࢖ͬͨ
    ϦΞΫςΟϒϓϩάϥϛϯάΛҙࣝ͠ͳ͚Ε͹ͳΒͳ͍ͨΊɺ
    ೉қ౓্͕͕Δ
    ▸ ͜ͷઅͰ͸͋͘·Ͱʮ8FC$MJFOUΛ࢖͏ͱ͜͏ͳΔΑʯ
    ͱ͍͏ྫΛ঺հ

    View Slide

  49. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    8FC$MJFOUΛ4QSJOH.7$্Ͱ࢖͏


    org.springframework.boot
    spring-boot-starter-web


    org.springframework.boot
    spring-boot-starter-webflux

    ▸ TQSJOHCPPUTUBSUFSXFC .7$
    ͱ
    TQSJOHCPPUTUBSUFSXFCqVY 8FC'MVY
    ͷ྆ํΛ
    ґଘੑʹؚΊΔͱɺ4QSJOH.7$͕༏ઌ͞ΕΔ
    ▸ IUUQTEPDTTQSJOHJPTQSJOHCPPUEPDTDVSSFOUSFGFSFODF
    IUNMTJOHMFCPPUGFBUVSFTXFCFOWJSPONFOU

    View Slide

  50. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    8FC$MJFOUͷ#FBOఆٛ

    @Bean
    public WebClient webClient(...) {
    // λΠϜΞ΢τΛઃఆ
    Function super TcpClient, ? extends TcpClient> tcpMapper =
    tcpClient -> {
    // Connect TimeoutΛઃఆ
    return tcpClient.option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
    .doOnConnected(conn -> conn
    // Read TimeoutΛઃఆ
    .addHandlerLast(
    new ReadTimeoutHandler(1000, TimeUnit.MILLISECONDS))
    // Write TimeoutΛઃఆ
    .addHandlerLast(
    new WriteTimeoutHandler(1000, TimeUnit.MILLISECONDS))
    );
    };
    // ࣍ϖʔδʹଓ͘
    λΠϜΞ΢τઃఆΛ๨Εͣʹʂ

    View Slide

  51. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    8FC$MJFOUͷ#FBOఆٛʢଓ͖ʣ

    // લϖʔδ͔Βͷଓ͖
    HttpClient httpClient = HttpClient.create().tcpConfiguration(tcpMapper);
    // OAuth2ؔ࿈ͷઃఆ
    ServletOAuth2AuthorizedClientExchangeFilterFunction oAuth2Client =
    new ServletOAuth2AuthorizedClientExchangeFilterFunction(
    clientRegistrationRepository, authorizedClientRepository);
    return builder.baseUrl(resourceServerUri)
    // ࡞੒ͨ͠HttpClientΛ௥Ճ
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    // OAuth2ઃఆΛ௥Ճ
    .apply(oAuth2Client.oauth2Configuration())
    ...
    .build();
    }

    View Slide

  52. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4FSWMFU0"VUI"VUIPSJ[FE$MJFOU
    &YDIBOHF'JMUFS'VODUJPO͸ԿΛͯ͘͠ΕΔ͔
    ▸ 8FC$MJFOU͔ΒͷϦΫΤετ࣌ʹ
    Authorization: Bearer ΞΫηετʔΫϯ
    Λϔομʔʹ௥Ճͯ͘͠ΕΔ
    ▸ ΞΫηετʔΫϯͷ༗ޮظݶ͕੾Ε͍ͯͨΒ
    ϦϑϨογϡͯ͘͠ΕΔ

    View Slide

  53. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ϦϑϨογϡͷ࢓૊Έ

    ServletOAuth2AuthorizedClientExchangeFilterFunction
    DefaultOAuth2AuthorizedClientManager
    DelegatingOAuth2AuthorizedClientProvider
    RefreshTokenOAuth2AuthorizedClientProvider
    DefaultRefreshTokenTokenResponseClient
    ݺͼग़͠
    ݺͼग़͠
    ݺͼग़͠
    ݺͼग़͠

    View Slide

  54. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    %FGBVMU3FGSFTI5PLFO5PLFO3FTQPOTF$MJFOU
    ▸ 3FTU5FNQMBUFͰೝՄαʔόʔʹΞΫηεͯ͠ɺ
    ΞΫηετʔΫϯͷϦϑϨογϡΛߦ͏
    ▸ ৄࡉ͸Լهͷهࣄࢀর
    ▸ 4QSJOH4FDVSJUZYͰ0"VUIΞΫηετʔΫϯΛ
    ϦϑϨογϡ͢Δ
    [email protected]
    GCGDFCF

    View Slide

  55. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    %FGBVMU3FGSFTI5PLFO5PLFO3FTQPOTF$MJFOU
    ͷ஫ҙ఺
    ▸ σϑΥϧτͰ͸ɺ
    ಺෦Ͱ࢖͍ͬͯΔRestTemplateʹ
    λΠϜΞ΢τ͕ઃఆ͞Ε͍ͯͳ͍
    ˠԼهͷΑ͏ʹઃఆ

    DefaultRefreshTokenTokenResponseClient tokenResponseClient =
    new DefaultRefreshTokenTokenResponseClient();
    RestTemplate restTemplate = restTemplateBuilder
    .setConnectTimeout(Duration.ofMillis(1000))
    .setReadTimeout(Duration.ofMillis(1000))
    ...
    .build();
    tokenResponseClient.setRestOperations(restTemplate);

    View Slide

  56. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4FSWMFU0"VUI"VUIPSJ[FE$MJFOU
    &YDIBOHF'JMUFS'VODUJPOʹλΠϜΞ΢τΛઃఆ

    ServletOAuth2AuthorizedClientExchangeFilterFunction
    DefaultOAuth2AuthorizedClientManager
    OAuth2AuthorizedClientProvider
    RestTemplateʢλΠϜΞ΢τઃఆࡁΈʣ
    ୅ೖ
    ୅ೖ
    ୅ೖ
    ୅ೖ
    DefaultRefreshTokenTokenResponseClient

    View Slide

  57. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4FSWMFU0"VUI"VUIPSJ[FE$MJFOU
    &YDIBOHF'JMUFS'VODUJPOʹλΠϜΞ΢τΛઃఆ

    ▸ ۩ମతͳίʔυ͸ϝνϟ௕͍ͷͰ(JU)VCࢀর
    ▸ IUUQTHJUIVCDPN.BTBUPTIJ5BEBPBVUIXJUI
    TQSJOHTFDVSJUZCMPCNBTUFSDMJFOUKXUTSDNBJO
    KBWBDPNFYBNQMFDMJFOUKXU
    $MJFOU+XU"QQMJDBUJPOKBWB-

    View Slide

  58. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    *TTVFཱͯ·ͨ͠
    ▸ ੋඇʮ͍͍Ͷʯ͍ͩ͘͞
    ▸ IUUQTHJUIVCDPNTQSJOHQSPKFDUTTQSJOHTFDVSJUZ
    JTTVFT

    View Slide

  59. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  60. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ґଘੑ


    org.springframework.boot

    spring-boot-starter-oauth2-resource-server


    wTQSJOHTFDVSJUZDPOpH
    wTQSJOHTFDVSJUZPBVUISFTPVSDFTFSWFS
    wTQSJOHTFDVSJUZPBVUIKPTF
    ͳͲؚ͕·Ε͍ͯΔ

    View Slide

  61. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    BQQMJDBUJPOZNM

    spring.security.oauth2.resourceserver.jwt:
    jwk-set-uri: JWK Set͕ฦͬͯ͘ΔURL
    issuer-uri: ೝՄαʔόʔͷIssuer Identifier
    ※Keycloakͷ৔߹ɺissuer-uriΛࢦఆ͢Ε͹jwk-set-uri͸ࢦఆෆཁ

    View Slide

  62. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +BWB$POpH

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    ...
    http.authorizeRequests()
    .mvcMatchers("อޢର৅ͷURL")
    .hasAuthority("SCOPE_είʔϓ໊")
    ...;
    http.oauth2ResourceServer()
    .jwt();
    ...
    }
    }

    View Slide

  63. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOH4FDVSJUZ'JMUFS$IBJO

    SecurityContextPersistenceFilter
    LogoutFilter
    BearerTokenAuthenticationFilter
    ExceptionTranslationFilter
    FilterSecurityInterceptor
    ϦΫΤετ
    ड৴ͨ͠+85Λ࢖ͬͯ
    ೝূ͢Δ

    View Slide

  64. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    #FBSFS5PLFO"VUIFOUJDBUJPO'JMUFS಺Ͱͷॲཧ

    BearerTokenAuthenticationFilter
    ProviderManager
    JwtAuthenticationProvider
    NimbusJwtDecoder
    ᶃϦΫΤετϔομʔͰ
    ɹ+85จࣈྻΛड͚औΔ
    ᶄ+85จࣈྻΛ࣋ͬͨ
    ɹ"VUIFOUJDBUJPOΛ౉͢
    ᶅ+85จࣈྻΛ࣋ͬͨ
    ɹ"VUIFOUJDBUJPOΛ౉͢
    ᶆ+85จࣈྻΛ౉͢
    ᶇ+85จࣈྻΛݕূޙɺ
    ɹ+XUΦϒδΣΫτʹม׵
    ᶈ+XU͔Β"VUIPSJUZΛநग़ɹ
    ɹˠ"VUIFOUJDBUJPOΛฦ͢
    ᶉ"VUIFOUJDBUJPOΛฦ͢
    ᶊ4FDVSJUZ$POUFYUʹɹ
    ɹ"VUIFOUJDBUJPOΛอଘ
    ݕূࣦഊ࣌͸
    ྫ֎ൃੜ

    View Slide

  65. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  66. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +85ܗࣜΞΫηετʔΫϯͷ໰୊఺
    ▸ +85ʹؚ·Ε͍ͯͳ͍৘ใ͸औಘͰ͖ͳ͍
    ▸ +85ʹؚΉ৘ใ͕ଟ͗͢Δͱ
    τʔΫϯࣗମ͕େ͖͘ͳͬͯ͠·͏
    ▸ ೝՄαʔόʔଆͰ
    ΞΫηετʔΫϯΛແޮԽͰ͖ͳ͍

    View Slide

  67. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ͦ͜Ͱ5PLFO*OUSPTQFDUJPOʂ
    ▸ 3'$
    ▸ IUUQTUPPMTJFUGPSHIUNMSGD
    ▸ Ϧιʔεαʔόʔ͕ೝՄαʔόʔʹ
    ΞΫηετʔΫϯΛૹ৴͢Δ͜ͱͰɺ
    ᶃΞΫηετʔΫϯࣗମʹؚ·Ε͍ͯͳ͍৘ใΛ
    औಘͰ͖Δ
    ᶄΞΫηετʔΫϯͷ༗ޮੑΛνΣοΫͰ͖Δ

    View Slide

  68. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ϦΫΤετ

    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε
    αʔόʔ
    ೝՄ
    αʔόʔ
    POST /introspect HTTP/1.1
    Host: keycloak.example.com
    Accept: application/json
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic dXNlcjpwYXNzd29yZAo=
    token=ΞΫηετʔΫϯ

    View Slide

  69. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    Ϩεϙϯε

    ੥ٻॻ࡞੒

    ࢿྉ༣ૹ
    Ϧιʔε
    αʔόʔ
    ೝՄ
    αʔόʔ
    HTTP/1.1 200 OK
    Content-Type: application/json
    {
    "active": true·ͨ͸false,
    "client_id": "ΫϥΠΞϯτͷID",
    "username": "ϦιʔεΦʔφʔͷϢʔβʔ໊",
    "scope": "είʔϓ",
    ...
    }

    View Slide

  70. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    Ϧιʔεαʔόʔͷೝূํ๏
    ▸ ۩ମతͳํ๏͸ɺ࢓༷Ͱ͸ఆ·͍ͬͯͳ͍
    ▸ 4QSJOH4FDVSJUZͷσϑΥϧτ͸#BTJDೝূ
    ▸ NimbusOpaqueTokenIntospector͕
    RestTemplateΛ࢖࣮ͬͯߦ
    ▸ ଞͷํ๏ʹΧελϚΠζՄೳʢޙड़ʣ

    View Slide

  71. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    BQQMJDBUJPOZNM

    spring.security.oauth2.resourceserver.opaquetoken:
    client-id: ϦιʔεαʔόʔͷID
    client-secret: Ϧιʔεαʔόʔͷύεϫʔυ
    introspection-uri: ೝՄαʔόʔͷ
    ɹɹɹɹɹɹɹɹɹɹɹɹ ΠϯτϩεϖΫγϣϯΤϯυϙΠϯτ

    View Slide

  72. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    +BWB$POpH

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.oauth2ResourceServer()
    .opaqueToken();
    }
    }

    View Slide

  73. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOH4FDVSJUZ'JMUFS$IBJO

    SecurityContextPersistenceFilter
    LogoutFilter
    BearerTokenAuthenticationFilter
    ExceptionTranslationFilter
    FilterSecurityInterceptor
    ϦΫΤετ
    ड৴ͨ͠ΞΫηετʔΫϯΛ
    ࢖ͬͯೝূ͢Δ

    View Slide

  74. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    #FBSFS5PLFO"VUIFOUJDBUJPO'JMUFS಺Ͱͷॲཧ

    BearerTokenAuthenticationFilter
    ProviderManager
    OpaqueTokenAuthenticationProvider
    NimbusOpaqueTokenIntrospector
    ᶃϦΫΤετϔομʔͰ
    ɹΞΫηετʔΫϯΛड͚औΔ
    ᶄΞΫηετʔΫϯΛ࣋ͬͨ
    ɹ"VUIFOUJDBUJPOΛ౉͢
    ᶅΞΫηετʔΫϯΛ࣋ͬͨ
    ɹ"VUIFOUJDBUJPOΛ౉͢
    ᶆΞΫηετʔΫϯΛ౉͢
    ᶇ5PLFO*OUSPTQFDUJPO࣮ߦ
    ɹˠ0"VUI"VUIFOUJDBUJPO
    ɹɹ1SJODJQBMΛฦ͢
    ᶈ"VUIFOUJDBUJPOΛฦ͢
    ᶉ"VUIFOUJDBUJPOΛฦ͢
    ᶊ4FDVSJUZ$POUFYUʹɹ
    ɹ"VUIFOUJDBUJPOΛอଘ
    ݕূࣦഊ࣌͸
    ྫ֎ൃੜ

    View Slide

  75. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝূํ๏ͷΧελϚΠζ

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.oauth2ResourceServer()
    .opaqueToken()
    .introspector(new MyIntrospector());
    }
    }
    public class MyIntrospector
    implements OpaqueTokenIntrospector {
    ...
    }

    View Slide

  76. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΧελϚΠζྫ

    ▸ NimbusOpaqueTokenIntospector಺ͷ
    RestTemplateʹλΠϜΞ΢τΛઃఆ
    ▸ σϑΥϧτͰ͸λΠϜΞ΢τແ͠ͳͷͰɺ
    ઃఆͨ͠΄͏͕Α͍

    View Slide

  77. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΧελϚΠζྫ

    @Configuration
    public class IntrospectorConfig {
    @Bean
    public NimbusOpaqueTokenIntrospector introspector(
    RestTemplateBuilder builder,
    OAuth2ResourceServerProperties prop) {
    OAuth2ResourceServerProperties.Opaquetoken opaquetoken =
    prop.getOpaquetoken();
    RestTemplate rest = builder
    .setReadTimeout(Duration.ofMillis(1000))
    .setConnectTimeout(Duration.ofMillis(1000))
    .basicAuthentication(opaquetoken.getClientId(),
    opaquetoken.getClientSecret())
    .build();
    return new NimbusOpaqueTokenIntrospector(
    opaquetoken.getOpaquetoken().getIntrospectionUri(), rest);
    }
    }
    λΠϜΞ΢τઃఆࡁΈͷ
    RestTemplateΛར༻͢Δ
    NimbusOpaqueToken
    IntrospectorΛ#FBOఆٛ

    View Slide

  78. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ΧελϚΠζྫ

    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    OpaqueTokenIntrospector introspector;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    http.oauth2ResourceServer()
    .opaqueToken()
    .introspector(introspector);
    }
    ΧελϚΠζͨ͠
    NimbusOpaqueTokenIntrospector
    ͷ#FBOΛࢦఆ

    View Slide

  79. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  80. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    5PLFO1SPQBHBUJPOͱ͸
    ▸ தؒͷϚΠΫϩαʔϏε͸ɺ
    ࣗ෼͕ड͚औͬͨΞΫηετʔΫϯΛ
    ͦͷ··ԼྲྀͷϚΠΫϩαʔϏεʹ౉͢

    $MJFOU
    "1*
    (BUFXBZ
    3FTPVSDF
    4FSWFS
    ΞΫηε
    τʔΫϯ
    ΞΫηε
    τʔΫϯ

    View Slide

  81. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    5PLFO1SPQBHBUJPOͷઃఆ
    ▸ WebClientʹ
    ServletBearerExchangeFilterFunction
    Λ௥Ճ

    @Bean
    public WebClient webClient(...) {
    ...
    return builder.baseUrl(resourceServerUri)
    .clientConnector(new ReactorClientHttpConnector(httpClient))
    .filter(new ServletBearerExchangeFilterFunction())
    ...
    .build();
    }

    View Slide

  82. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    5PLFO1SPQBHBUJPOͷ࢓૊Έ
    ▸ ϦΫΤετૹ৴લʹ
    ᶃ "VUIFOUJDBUJPO͔ΒΞΫηετʔΫϯΛऔಘ
    ᶄ "VUIPSJ[BUJPOϔομʔʹΞΫηετʔΫϯΛ௥Ճ
    ‣ ৄࡉ͸͜͜Β΁Μͷίʔυࢀর
    ‣ IUUQTHJUIVCDPNTQSJOHQSPKFDUTTQSJOHTFDVSJUZCMPC
    NBTUFSPBVUIPBVUISFTPVSDFTFSWFSTSDNBJOKBWBPSH
    TQSJOHGSBNFXPSLTFDVSJUZPBVUITFSWFSSFTPVSDFXFC
    SFBDUJWFGVODUJPODMJFOU
    4FSWMFU#FBSFS&YDIBOHF'JMUFS'VODUJPOKBWB-

    View Slide

  83. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    3FTU5FNQMBUFΛ࢖͍͍ͨ৔߹
    ▸ ಉ౳ͷػೳΛࣗ෼Ͱ࡞Δඞཁ͕͋Δ
    ▸ ίʔυྫ͸ϦϑΝϨϯεࢀর
    IUUQTEPDTTQSJOHJPTQSJOHTFDVSJUZTJUFEPDT
    3&-&"4&SFGFSFODFIUNMSFTUUFNQMBUF
    TVQQPSU

    View Slide

  84. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ໨࣍
    ▸ 0"VUIΛβοͱ෮श
    ▸ ΫϥΠΞϯτͷجຊػೳͱߏ଄
    ▸ ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻
    ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ଄
    ▸ 5PLFO*OUSPTQFDUJPO
    ▸ 5PLFO1SPQBHBUJPO
    ▸ ·ͱΊ

    View Slide

  85. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ·ͱΊ
    ▸ λΠϜΞ΢τઃఆɺେࣄɻ

    View Slide

  86. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ೝՄαʔόʔ͸ʁ
    ▸ 4QSJOH"VUIPSJ[BUJPO4FSWFS͕։ൃਐߦத

    https://spring.io/blog/2020/08/21/get-the-very-first-bits-of-spring-authorization-server-0-0-1

    View Slide

  87. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    4QSJOH4FDVSJUZϦϑΝϨϯε
    ▸ ࠓճ঺հ͍ͯ͠ͳ͍ػೳ΍ɺ༷ʑͳΧελϚΠζ
    ํ๏͕঺հ͞Ε͍ͯ·͢
    ▸ IUUQTEPDTTQSJOHJPTQSJOHTFDVSJUZTJUF
    EPDT3&-&"4&SFGFSFODFIUNM
    PBVUI

    View Slide

  88. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUIؔ࿈ॻ੶

    View Slide

  89. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    0"VUI࢓༷ॻ
    ▸ 3'$5IF0"VUI"VUIPSJ[BUJPO
    'SBNFXPSL
    ▸ IUUQTUPPMTJFUGPSHIUNMSGD
    ▸ 3'$0"VUI5PLFO*OUSPTQFDUJPO
    ▸ IUUQTUPPMTJFUGPSHIUNMSGD

    View Slide

  90. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    <3*1>౎ݩ͞Μͷࢿྉ
    ▸ ϚΠΫϩαʔϏε࣌୅ͷೝূͱೝՄ
    [email protected]
    TT
    ▸ جૅ͔Βͷ0"VUI
    [email protected]
    EFWFMPQFSTJP

    View Slide

  91. $
    $"4"3&"- *OD"MMSJHIUTSFTFSWFE
    #jjug_ccc
    ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ

    View Slide