Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
OAuth 2.0 with Spring Security #jjug_ccc #jjug_ccc_b / oauth2-with-spring-security
Search
Masatoshi Tada
November 07, 2020
Technology
4
1.8k
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
Share
More Decks by Masatoshi Tada
See All by Masatoshi Tada
プロになるためのSpring上級知識 #jsug / advanced-spring-for-professionals
masatoshitada
3
1.9k
OpenID Connect 1.0 with Spring Security #jjug_ccc #jjug_ccc_b / oidc-with-spring-security
masatoshitada
1
1.3k
Flaskのセキュリティどうしてます?アクセス制御ライブラリCasbin入門! #pycharity / flask-authz-with-casbin
masatoshitada
0
830
今こそ知りたいSpring DI×AOP / spring-di-aop-for-every-developers
masatoshitada
4
1.9k
基礎から分かる!アプリケーション開発者のためのKubernetes入門 / kubernetes-basics-for-application-developers
masatoshitada
10
3.5k
2時間で分かる!Kubernetesとは何なのか / what-is-kubernetes
masatoshitada
0
890
Introduction to Resilience4j
masatoshitada
2
1k
SpringOne Platform 2019報告会 -概要、Resilience4j、LT- #jsug / springone-platform-2019
masatoshitada
0
1.1k
From Hystrix To Resilience4j
masatoshitada
1
1k
Other Decks in Technology
See All in Technology
テストプロセスで大事にしていること #jasstnano
makky_tyuyan
0
160
レガシーをぶっ壊せ。AEONで始めるDevRelの話 / Qiita Night 2024-2-22
aeonpeople
3
1.3k
Janus
bkuhlmann
1
490
20分で完全に理解するGrafanaダッシュボード
hamadakoji
1
210
ExaDB-D dbaascli で出来ること
oracle4engineer
PRO
0
2k
MapLibreとAmazon Location Service
dayjournal
1
150
現代CSSフレームワークの内部実装とその仕組み
poteboy
8
3.6k
アクセシビリティを考慮したUI/CSSフレームワーク・ライブラリ選定
yajihum
2
1k
Meta Quest 3 で動く桜マシマシ WebXR アプリを IBM Cloud Code Engine と Babylon.js で作った話
1ftseabass
PRO
0
120
Postman v10リリース後を振り返る / Looking back at Postman v10 after release
yokawasa
1
150
Oracle Cloud Infrastructure:2024年4月度サービス・アップデート
oracle4engineer
PRO
1
190
Terraformあれやこれ/terraform-this-and-that
emiki
8
1.3k
Featured
See All Featured
Building Flexible Design Systems
yeseniaperezcruz
319
37k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
78
42k
Documentation Writing (for coders)
carmenintech
60
3.9k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
357
22k
Fashionably flexible responsive web design (full day workshop)
malarkey
398
65k
Testing 201, or: Great Expectations
jmmastey
28
6.3k
Adopting Sorbet at Scale
ufuk
68
8.6k
Atom: Resistance is Futile
akmur
259
25k
Cheating the UX When There Is Nothing More to Optimize - PixelPioneers
stephaniewalter
274
13k
No one is an island. Learnings from fostering a developers community.
thoeni
16
2.1k
What's in a price? How to price your products and services
michaelherold
237
11k
Visualization
eitanlees
136
14k
Transcript
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUI XJUI 4QSJOH4FDVSJUZ ג ΧαϨΞϧଟాਅහ ݄
++6($$$'BMM
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ͜ͷηογϣϯʹ͍ͭͯ ▸ 4QSJOH4FDVSJUZͷ0"VUIؔ࿈ػೳΛɺ ΈؚΊ͔ͯΓ͘͢ղઆ͠·͢ ▸ αϯϓϧίʔυ
▸ IUUQTHJUIVCDPN.BTBUPTIJ5BEBPBVUIXJUI TQSJOHTFDVSJUZ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ඞཁͳલఏࣝ ▸ ͜ͷηογϣϯʲதڃऀ͚ʳͰ͢ ▸ ҎԼͷલఏ͕ࣝඞཁͰ͢ ▸
"VUIPSJ[BUJPO$PEF(SBOU'MPXΛઆ໌Ͱ͖Δ ▸ 4QSJOH4FDVSJUZΛͬͨ͜ͱ͕͋Δ ▸ 0"VUIػೳͰͳͯ͘0,
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ઌʹ݁ ▸ 4QSJOH4FDVSJUZ෦ͷRestTemplateʹɺ λΠϜΞτ͕ઃఆ͞Ε͍ͯͳ͍͜ͱ͕ ΄ͱΜͲ ˠͪΌΜͱλΠϜΞτΛઃఆ͠·͠ΐ͏
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUIͷجૅΛΓ͍ͨํʜ https://www.slideshare.net/masatoshitada7/oauth-20spring-security-51-121418814
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOH4FDVSJUZͷΞʔΩςΫνϟΛΓ͍ͨํʜ https://www.slideshare.net/masatoshitada7/spring-security-meetup
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣗݾհ ▸ ଟాਅහʢ!TVLF@NBTBʣ ▸ ݚमτϨʔφʔ!ΧαϨΞϧ ▸
+BWB(PMBOH.JDSPTFSWJDFT ,VCFSOFUFT1ZUIPOػցֶश ▸ 7.XBSFೝఆߨࢣ ▸ ຊ4QSJOHϢʔβձελοϑ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ઌʹ͓ͼ͓͖ͯ͠·͢ ▸ ່ࢯʢϲ݄ʣͷ͕ͱ͜ΖͲ͜ΖೖΔ͔ ͠Ε·ͤΜ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc גࣜձࣾΧαϨΞϧ ▸ ଞࣾʹແ͍৭ʑͳϓϩάϥϛϯάݴޠͷ ݚमΛఏڙ͍ͯ͠·͢ʂ /&8
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOHܥίʔε ▸ جૅ͔Βͷ4QSJOH#PPUʹΑΔ 8FCΞϓϦέʔγϣϯ։ൃʢؒʣ ▸
7.XBSF5BO[Vೝఆ4QSJOH$PSF5SBJOJOHʢؒʣ ▸ 7.XBSF5BO[Vೝఆ4QSJOH$MPVE%FWFMPQFSʢؒʣ ▸ جૅ͔Βͷ4QSJOH4FDVSJUZʢؒʣ ▸ جૅ͔Βͷ4QSJOH#BUDIʢؒʣ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ৽نίʔεϦϦʔε (PݴޠʹΑΔ ΫϥυωΠςΟϒΞϓϦέʔγϣϯ։ൃ جຊจ๏ɺ8FCΞϓϦέʔγϣϯɺϚΠΫϩαʔϏε 1ZUIPOೖ
جຊจ๏ɺϥΠϒϥϦͷར༻ɺ8FCεΫϨΠϐϯά 1ZUIPOʹΑΔػցֶशೖʢԾʣ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΦϯϥΠϯݚमɺ͡Ί·ͨ͠ ߨࢣ डߨऀ༷ ▸ ʮֶशޮՌ௨ৗͱมΘΒͳ͍ʯ
ͱධͰ͢ʂ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUIͱ ▸ ೝՄͷྲྀΕΛنఆͨ͠ϓϩτίϧ ▸ 3'$ ຊޠ൛͋Δ
▸ 0"VUIͱผ ▸ 4USVUTͱ4USVUT͘Β͍ҧ͏ ▸ ೝূϓϩτίϧ0QFO*%$POOFDU ͷϕʔεʹͳ͍ͬͯΔ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUIͷొਓ ᶃ ϦιʔεΦʔφʔ 3FTPVSDF0XOFS ▸
ใͷ࣋ͪओɻଟ͘ͷέʔεͰਓؒɻ ᶄ Ϧιʔεαʔόʔ 3FTPVSDF4FSWFS ▸ ใΛอ࣋͢Δαʔόʔɻ ᶅ ΫϥΠΞϯτ $MJFOU ▸ Ϧιʔεαʔόʔ͔ΒΒͬͨใΛѻ͏ΞϓϦέʔγϣϯɻ ᶆ ೝՄαʔόʔ "VUIPSJ[BUJPO4FSWFS ▸ ΞΫηετʔΫϯΛൃߦ͢Δαʔόʔɻ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 5XJUUFSͷྫͰొਓ·ͱΊ twitter.com ͜Μʹͪ! ָ͠Έͩͳʔ Ϧιʔε
Φʔφʔ ΫϥΠΞϯτ Ϧιʔεαʔόʔ ೝՄαʔόʔ ೝՄ ΞΫηε τʔΫϯ ༩ ΞΫηε τʔΫϯ ͭͿ͖ ※ຊTwitterOAuth 1.0Λ͍ͬͯ·͢
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc άϥϯτλΠϓʢΞΫηετʔΫϯͷऔಘํ๏ʣ ᶃ ೝՄίʔυ ▸ ओʹαʔόʔαΠυ8FCΞϓϦέʔγϣϯ ᶄ
ΠϯϓϦγοτʢඇਪʣ ▸ ओʹΫϥΠΞϯταΠυ8FCΞϓϦέʔγϣϯ ᶅ ϦιʔεΦʔφʔύεϫʔυΫϨσϯγϟϧʢඇਪʣ ▸ ओʹެࣜͷεϚϗΞϓϦͳͲ ᶆ ΫϥΠΞϯτΫϨσϯγϟϧ ▸ ΫϥΠΞϯτࣗͷใऔಘ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc <ࢀߟ>0"VUIͷ༷ࡦఆ͕ਐߦத ▸ 0"VUIͷ༷ʴͦͷଞΛ࠶ཧͨ͠ͷ ˠطʹඇਪͱͳ͍ͬͯΔػೳ͕আ͞ΕΔ ▸ ΠϯϓϦγοτ
▸ ϦιʔεΦʔφʔύεϫʔυΫϨσϯγϟϧ ▸ ৄࡉͪ͜Βͷهࣄ ▸ 0"VUIͷඪ४Խ͕ਐΊΒΕ͍ͯ·͢ IUUQTRJJUBDPNqBOP@ZVLJJUFNTCGBFFFCFFEDD ▸ 4QSJOH4FDVSJUZͷ0"VUIରԠ༧ఆɺݱ࣌Ͱෆ໌
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ ᶅೝՄը໘
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ ᶅೝՄը໘ ᶆೝՄ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶇೝՄίʔυൃߦʴϦμΠϨΫτ ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ ᶅೝՄը໘ ᶆೝՄ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶇೝՄίʔυൃߦʴϦμΠϨΫτ ᶈೝՄίʔυ ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ ᶅೝՄը໘ ᶆೝՄ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ೝՄίʔυʹΑΔΞΫηετʔΫϯऔಘ ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ※ ※Webϒϥβɺ༷ॻͰʮϢʔβʔΤʔδΣϯτʯͱهࡌ͞Ε͍ͯ·͢ ᶃॳճΞΫηε ᶇೝՄίʔυൃߦʴϦμΠϨΫτ ᶈೝՄίʔυ ᶉΞΫηετʔΫϯ ᶄೝՄΤϯυϙΠϯτʹϦμΠϨΫτ ᶅೝՄը໘ ᶆೝՄ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶅΞΫηε ɹτʔΫϯ ɹݕূ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶅΞΫηε ɹτʔΫϯ ɹݕূ ᶆݕূ݁ՌΛฦ͢ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶅΞΫηε ɹτʔΫϯ ɹݕূ ᶆݕূ݁ՌΛฦ͢ ᶇݕূ݁ՌΛ ɹ֬ೝ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶅΞΫηε ɹτʔΫϯ ɹݕূ ᶆݕূ݁ՌΛฦ͢ ᶈϨεϙϯε ᶇݕূ݁ՌΛ ɹ֬ೝ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΞΫηετʔΫϯΛར༻ͨ͠ϦιʔεΞΫηε ೝՄαʔόʔ ΫϥΠΞϯτ Ϧιʔε Φʔφʔ
Web ϒϥβ ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ ᶃϦΫΤετ ᶅΞΫηε ɹτʔΫϯ ɹݕূ ᶆݕূ݁ՌΛฦ͢ ᶈϨεϙϯε ᶉϨεϙϯε ᶇݕূ݁ՌΛ ɹ֬ೝ ᶄϦιʔεʹΞΫηε with ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ґଘੑ <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-oauth2-client
</artifactId> </dependency> wTQSJOHTFDVSJUZDPOpH wTQSJOHTFDVSJUZPBVUIDMJFOU ͳͲؚ͕·Ε͍ͯΔ
$ $"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Ͱ͢
$ $"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ҙʣ
$ $"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(); ... } } ϩάΠϯʹؔ͢Δઃఆ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOH4FDVSJUZ'JMUFS$IBJO SecurityContextPersistenceFilter LogoutFilter OAuth2AuthorizationRequestRedirectFilter OAuth2LoginAuthenticationFilter
ExceptionTranslationFilter FilterSecurityInterceptor ϦΫΤετ ೝՄΤϯυϙΠϯτʹ ϦμΠϨΫτ͢Δ ೝূΛߦ͏
$ $"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
$ $"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Λอଘ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc %FGBVMU"VUIPSJ[BUJPO$PEF5PLFO3FTQPOTF$MJFOU ▸ RestTemplateͰೝՄαʔόʔʹ ΞΫηεͯ͠ɺΞΫηετʔΫϯͷऔಘΛߦ͏ ▸ ͜ͷRestTemplateʹɺσϑΥϧτͰ
λΠϜΞτ͕ઃఆ͞Ε͍ͯͳ͍
$ $"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; }
$ $"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ࢀরʣ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 8FC$MJFOUͱʁ ▸ 4QSJOH8FC'MVYʹؚ·Ε͍ͯΔɺ ϦΞΫςΟϒͳ)551ΫϥΠΞϯτ ▸ 3FBDUPSͷ'MVY.POPΛ׆༻
▸ ྲྀΕΔΑ͏ͳ"1* public List<Todo> findAll() { return webClient.get() .uri("/todos") .retrieve() .bodyToFlux(Todo.class) .collectList() .block(); }
$ $"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ͷར༻Λݕ౼ͯ͠
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 8FC$MJFOUʹҠߦ͖͔͢ʁ ▸ ·ͩ͘3FTU5FNQMBUFͰΑ͍ ଟాݸਓͷҙݟ ▸
ΞϓϦέʔγϣϯ4QSJOHຊମͳͲͷӨڹ͕ඇৗʹେ͖͍ ͨΊɺ3FTU5FNQMBUF͕͙͢ʹআ͞ΕΔͱࢥ͑ͳ͍ ▸ 8FC$MJFOUΛ͏ͱɺͲ͏ͯ͠'MVY.POPΛͬͨ ϦΞΫςΟϒϓϩάϥϛϯάΛҙࣝ͠ͳ͚ΕͳΒͳ͍ͨΊɺ қ্͕͕Δ ▸ ͜ͷઅͰ͋͘·Ͱʮ8FC$MJFOUΛ͏ͱ͜͏ͳΔΑʯ ͱ͍͏ྫΛհ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 8FC$MJFOUΛ4QSJOH.7$্Ͱ͏ <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency>
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-webflux</artifactId> </dependency> ▸ TQSJOHCPPUTUBSUFSXFC .7$ ͱ TQSJOHCPPUTUBSUFSXFCqVY 8FC'MVY ͷ྆ํΛ ґଘੑʹؚΊΔͱɺ4QSJOH.7$͕༏ઌ͞ΕΔ ▸ IUUQTEPDTTQSJOHJPTQSJOHCPPUEPDTDVSSFOUSFGFSFODF IUNMTJOHMFCPPUGFBUVSFTXFCFOWJSPONFOU
$ $"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)) ); }; // ࣍ϖʔδʹଓ͘ λΠϜΞτઃఆΛΕͣʹʂ
$ $"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(); }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4FSWMFU0"VUI"VUIPSJ[FE$MJFOU &YDIBOHF'JMUFS'VODUJPOԿΛͯ͘͠ΕΔ͔ ▸ 8FC$MJFOU͔ΒͷϦΫΤετ࣌ʹ Authorization: Bearer
ΞΫηετʔΫϯ ΛϔομʔʹՃͯ͘͠ΕΔ ▸ ΞΫηετʔΫϯͷ༗ޮظݶ͕Ε͍ͯͨΒ ϦϑϨογϡͯ͘͠ΕΔ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ϦϑϨογϡͷΈ ServletOAuth2AuthorizedClientExchangeFilterFunction DefaultOAuth2AuthorizedClientManager DelegatingOAuth2AuthorizedClientProvider RefreshTokenOAuth2AuthorizedClientProvider
DefaultRefreshTokenTokenResponseClient ݺͼग़͠ ݺͼग़͠ ݺͼग़͠ ݺͼग़͠
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc %FGBVMU3FGSFTI5PLFO5PLFO3FTQPOTF$MJFOU ▸ 3FTU5FNQMBUFͰೝՄαʔόʔʹΞΫηεͯ͠ɺ ΞΫηετʔΫϯͷϦϑϨογϡΛߦ͏ ▸ ৄࡉԼهͷهࣄࢀর
▸ 4QSJOH4FDVSJUZYͰ0"VUIΞΫηετʔΫϯΛ ϦϑϨογϡ͢Δ IUUQTRJJUBDPNTVLF@NBTBJUFNT GCGDFCF
$ $"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);
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4FSWMFU0"VUI"VUIPSJ[FE$MJFOU &YDIBOHF'JMUFS'VODUJPOʹλΠϜΞτΛઃఆ ServletOAuth2AuthorizedClientExchangeFilterFunction DefaultOAuth2AuthorizedClientManager OAuth2AuthorizedClientProvider
RestTemplateʢλΠϜΞτઃఆࡁΈʣ ೖ ೖ ೖ ೖ DefaultRefreshTokenTokenResponseClient
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4FSWMFU0"VUI"VUIPSJ[FE$MJFOU &YDIBOHF'JMUFS'VODUJPOʹλΠϜΞτΛઃఆ ▸ ۩ମతͳίʔυϝνϟ͍ͷͰ(JU)VCࢀর ▸
IUUQTHJUIVCDPN.BTBUPTIJ5BEBPBVUIXJUI TQSJOHTFDVSJUZCMPCNBTUFSDMJFOUKXUTSDNBJO KBWBDPNFYBNQMFDMJFOUKXU $MJFOU+XU"QQMJDBUJPOKBWB-
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc *TTVFཱͯ·ͨ͠ ▸ ੋඇʮ͍͍Ͷʯ͍ͩ͘͞ ▸ IUUQTHJUIVCDPNTQSJOHQSPKFDUTTQSJOHTFDVSJUZ JTTVFT
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ґଘੑ <dependency> <groupId>org.springframework.boot</groupId> <artifactId> spring-boot-starter-oauth2-resource-server
</artifactId> </dependency> wTQSJOHTFDVSJUZDPOpH wTQSJOHTFDVSJUZPBVUISFTPVSDFTFSWFS wTQSJOHTFDVSJUZPBVUIKPTF ͳͲؚ͕·Ε͍ͯΔ
$ $"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ࢦఆෆཁ
$ $"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(); ... } }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOH4FDVSJUZ'JMUFS$IBJO SecurityContextPersistenceFilter LogoutFilter BearerTokenAuthenticationFilter ExceptionTranslationFilter
FilterSecurityInterceptor ϦΫΤετ ड৴ͨ͠+85Λͬͯ ೝূ͢Δ
$ $"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Λอଘ ݕূࣦഊ࣌ ྫ֎ൃੜ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc +85ܗࣜΞΫηετʔΫϯͷ ▸ +85ʹؚ·Ε͍ͯͳ͍ใऔಘͰ͖ͳ͍ ▸ +85ʹؚΉใ͕ଟ͗͢Δͱ τʔΫϯࣗମ͕େ͖͘ͳͬͯ͠·͏
▸ ೝՄαʔόʔଆͰ ΞΫηετʔΫϯΛແޮԽͰ͖ͳ͍
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ͦ͜Ͱ5PLFO*OUSPTQFDUJPOʂ ▸ 3'$ ▸ IUUQTUPPMTJFUGPSHIUNMSGD ▸
Ϧιʔεαʔόʔ͕ೝՄαʔόʔʹ ΞΫηετʔΫϯΛૹ৴͢Δ͜ͱͰɺ ᶃΞΫηετʔΫϯࣗମʹؚ·Ε͍ͯͳ͍ใΛ औಘͰ͖Δ ᶄΞΫηετʔΫϯͷ༗ޮੑΛνΣοΫͰ͖Δ
$ $"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=ΞΫηετʔΫϯ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc Ϩεϙϯε ٻॻ࡞ ࢿྉ༣ૹ Ϧιʔε αʔόʔ
ೝՄ αʔόʔ HTTP/1.1 200 OK Content-Type: application/json { "active": true·ͨfalse, "client_id": "ΫϥΠΞϯτͷID", "username": "ϦιʔεΦʔφʔͷϢʔβʔ໊", "scope": "είʔϓ", ... }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc Ϧιʔεαʔόʔͷೝূํ๏ ▸ ۩ମతͳํ๏ɺ༷Ͱఆ·͍ͬͯͳ͍ ▸ 4QSJOH4FDVSJUZͷσϑΥϧτ#BTJDೝূ ▸
NimbusOpaqueTokenIntospector͕ RestTemplateΛ࣮ͬͯߦ ▸ ଞͷํ๏ʹΧελϚΠζՄೳʢޙड़ʣ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc BQQMJDBUJPOZNM spring.security.oauth2.resourceserver.opaquetoken: client-id: ϦιʔεαʔόʔͷID client-secret:
Ϧιʔεαʔόʔͷύεϫʔυ introspection-uri: ೝՄαʔόʔͷ ɹɹɹɹɹɹɹɹɹɹɹɹ ΠϯτϩεϖΫγϣϯΤϯυϙΠϯτ
$ $"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(); } }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOH4FDVSJUZ'JMUFS$IBJO SecurityContextPersistenceFilter LogoutFilter BearerTokenAuthenticationFilter ExceptionTranslationFilter
FilterSecurityInterceptor ϦΫΤετ ड৴ͨ͠ΞΫηετʔΫϯΛ ͬͯೝূ͢Δ
$ $"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Λอଘ ݕূࣦഊ࣌ ྫ֎ൃੜ
$ $"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 { ... }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ΧελϚΠζྫ ▸ NimbusOpaqueTokenIntospectorͷ RestTemplateʹλΠϜΞτΛઃఆ ▸
σϑΥϧτͰλΠϜΞτແ͠ͳͷͰɺ ઃఆͨ͠΄͏͕Α͍
$ $"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ఆٛ
$ $"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Λࢦఆ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 5PLFO1SPQBHBUJPOͱ ▸ தؒͷϚΠΫϩαʔϏεɺ ͕ࣗड͚औͬͨΞΫηετʔΫϯΛ ͦͷ··ԼྲྀͷϚΠΫϩαʔϏεʹ͢
$MJFOU "1* (BUFXBZ 3FTPVSDF 4FSWFS ΞΫηε τʔΫϯ ΞΫηε τʔΫϯ
$ $"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(); }
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 5PLFO1SPQBHBUJPOͷΈ ▸ ϦΫΤετૹ৴લʹ ᶃ "VUIFOUJDBUJPO͔ΒΞΫηετʔΫϯΛऔಘ ᶄ
"VUIPSJ[BUJPOϔομʔʹΞΫηετʔΫϯΛՃ ‣ ৄࡉ͜͜ΒΜͷίʔυࢀর ‣ IUUQTHJUIVCDPNTQSJOHQSPKFDUTTQSJOHTFDVSJUZCMPC NBTUFSPBVUIPBVUISFTPVSDFTFSWFSTSDNBJOKBWBPSH TQSJOHGSBNFXPSLTFDVSJUZPBVUITFSWFSSFTPVSDFXFC SFBDUJWFGVODUJPODMJFOU 4FSWMFU#FBSFS&YDIBOHF'JMUFS'VODUJPOKBWB-
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 3FTU5FNQMBUFΛ͍͍ͨ߹ ▸ ಉͷػೳΛࣗͰ࡞Δඞཁ͕͋Δ ▸ ίʔυྫϦϑΝϨϯεࢀর IUUQTEPDTTQSJOHJPTQSJOHTFDVSJUZTJUFEPDT
3&-&"4&SFGFSFODFIUNMSFTUUFNQMBUF TVQQPSU
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ࣍ ▸ 0"VUIΛβοͱ෮श ▸ ΫϥΠΞϯτͷجຊػೳͱߏ ▸
ΫϥΠΞϯτͰͷ8FC$MJFOUͷར༻ ▸ Ϧιʔεαʔόʔͷجຊػೳͱߏ ▸ 5PLFO*OUSPTQFDUJPO ▸ 5PLFO1SPQBHBUJPO ▸ ·ͱΊ
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ·ͱΊ ▸ λΠϜΞτઃఆɺେࣄɻ
$ $"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
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 4QSJOH4FDVSJUZϦϑΝϨϯε ▸ ࠓճհ͍ͯ͠ͳ͍ػೳɺ༷ʑͳΧελϚΠζ ํ๏͕հ͞Ε͍ͯ·͢ ▸ IUUQTEPDTTQSJOHJPTQSJOHTFDVSJUZTJUF
EPDT3&-&"4&SFGFSFODFIUNM PBVUI
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUIؔ࿈ॻ੶
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc 0"VUI༷ॻ ▸ 3'$5IF0"VUI"VUIPSJ[BUJPO 'SBNFXPSL ▸ IUUQTUPPMTJFUGPSHIUNMSGD
▸ 3'$0"VUI5PLFO*OUSPTQFDUJPO ▸ IUUQTUPPMTJFUGPSHIUNMSGD
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc <3*1>ݩ͞Μͷࢿྉ ▸ ϚΠΫϩαʔϏε࣌ͷೝূͱೝՄ ▸ IUUQTXXXTMJEFTIBSFOFUEBJTVLF@N TT
▸ جૅ͔Βͷ0"VUI ▸ IUUQTXXXTMJEFTIBSFOFUEBJTVLF@NPBVUI EFWFMPQFSTJP
$ $"4"3&"- *OD"MMSJHIUTSFTFSWFE #jjug_ccc ͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ