Microsoft ID プラットフォ�`ムのアクセスト�`クンが ̄Invalid Signature ̄になる周 その2��Spring Security��
峻さん、こんにちは。室宝蝕�kグル�`プの稼-看噛温敬温稼です。
書定は避定だったんですね。避定の訳周は富し鹸�jで、��4で護り俳れる定は避定、�擇靴�し100で護り俳れる定は峠定、�曚燭世�400で護り俳れる定は避定、になります。
云籾です。
念指、Microsoft ID プラットフォ�`ムから�k佩されたアクセスト�`クンをGraph API參翌のリソ�`スサ�`バ�`で旋喘しようとすると、 ̄Invalid Signature ̄として屎しく�I尖してくれない���}を函り貧げました。書指は、この���}に��する���I圭隈をSpring Securityで盾�Qしたいと房います。 ̄Invalid Signature ̄に�vする圻咀や尖喇などについては、念指を歌孚してください。
朕肝
Graph API參翌のアクセスト�`クンを�k佩する圭隈
ゴ�`ル
盾�Qの圭��は念指と揖じです。1指朕のシ�`ケンスでは、OIDC�J�^��Graph API喘のアクセスト�`クンを�k佩して�Bいます。2指朕のシ�`ケンスでは、OAuth2.0により徭念で喘吭したリソ�`スサ�`バ�`へのアクセスト�`クンを�k佩して�Bいます。

或鴛禽遺範�^に駅勣な秤烏を譜協する
或鴛禽遺範�^で駅勣となる秤烏をapplication.propertiesに協吶します。
# 1指朕のシ�`ケンス��OIDC�J�^��Graph API喘アクセスト�`クン�k佩��
spring.security.oauth2.client.registration.microsoftonline.client-name=microsoftonline
spring.security.oauth2.client.registration.microsoftonline.client-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline.client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline.provider=microsoftonline
spring.security.oauth2.client.registration.microsoftonline.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.microsoftonline.redirect-uri={baseUrl}/login/oauth2/code/{registrationId}
spring.security.oauth2.client.provider.microsoftonline.issuer-uri: https://login.microsoftonline.com/{tenantId}/v2.0
spring.security.oauth2.client.provider.microsoftonline.authorization-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.microsoftonline.token-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
spring.security.oauth2.client.provider.microsoftonline.user-info-uri=https://graph.microsoft.com/oidc/userinfo
spring.security.oauth2.client.provider.microsoftonline.user-name-attribute=name
# 2指朕のシ�`ケンス��OAuth2.0によるアクセスト�`クン�k佩��
spring.security.oauth2.client.registration.microsoftonline4rsc.client-name=microsoftonline4rsc
spring.security.oauth2.client.registration.microsoftonline4rsc.client-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline4rsc.client-secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
spring.security.oauth2.client.registration.microsoftonline4rsc.provider=microsoftonline4rsc
spring.security.oauth2.client.registration.microsoftonline4rsc.authorization-grant-type=authorization_code
spring.security.oauth2.client.registration.microsoftonline4rsc.redirect-uri={baseUrl}/authorized/{registrationId}
spring.security.oauth2.client.registration.microsoftonline4rsc.scope=offline_access,yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy/.default
spring.security.oauth2.client.provider.microsoftonline4rsc.issuer-uri: https://login.microsoftonline.com/{tenantId}/v2.0
spring.security.oauth2.client.provider.microsoftonline4rsc.authorization-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/authorize
spring.security.oauth2.client.provider.microsoftonline4rsc.token-uri=https://login.microsoftonline.com/{tenantId}/oauth2/v2.0/token
1指朕のシ�`ケンスと、2指朕のシ�`ケンスに駅勣な秤�鵑鬚修譴召豢��xしています。�O協坪否に�vしては、Express + Passport�」�念?指、念指��と揖じなので�h苧を福待します。
協吶する縞のポイントとしては、プロパティ兆の{registrationId}何蛍を癖卷�筝�することです。箭えば1指朕シ�`ケンスの遺鉛庄艶稼岳鴛禽では、プロパティ兆がspring.security.oauth2.client.registration.microsoftonline.client-idとなっています。��して、2指朕シ�`ケンスの遺鉛庄艶稼岳鴛禽では、プロパティ兆がspring.security.oauth2.client.registration.microsoftonline4rsc.client-idです。この橿忖になっている倖侭により、それぞれを蛍けて協吶しています。
皆艶界顎姻庄岳霞酷庄鉛岳艶姻遺鞄温庄稼を伏撹する
參和は、1指朕のシ�`ケンスと、2指朕のシ�`ケンスの�I圭を佩う皆艶界顎姻庄岳霞酷庄鉛岳艶姻遺鞄温庄稼を伏撹するコ�`ドです。
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// 1指朕のシ�`ケンス��OIDC�J�^��Graph API喘アクセスト�`クン�k佩��
http
.authorizeHttpRequests(authorize -> authorize.anyRequest().authenticated())
.oauth2Login(oauth2 ->
oauth2
.loginPage(
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/microsoftonline"
)
);
// 2指朕のシ�`ケンス��OAuth2.0によるアクセスト�`クン�k佩��
http
.oauth2Client(Customizer.withDefaults())
.addFilterAfter(
this.createStartAuthorazationFilter(http, "microsoftonline4rsc"),
AuthorizationFilter.class
);
return http.build();
}1指朕のシ�`ケンスではoauth2.loginPage()にて、ログインに聞喘する譜協を峺協しています。枠ほど、application.propertiesに或鴛禽遺範�^および或粥顎岳鞄2.0で駅勣となる譜協として、microsoftonlineとmicrosoftonline4rscの2つを協吶しました。もし、oauth2.loginPage()を福待すると、皆沿姻庄稼乙皆艶界顎姻庄岳霞はどちらの譜協で範�^すれば措いのか登僅が竃栖ないため、參和の鮫中を燕幣してユ�`ザ�`に僉�kさせる強恬となります。書指はmicrosoftonlineで或鴛禽遺範�^したいので、oauth2.loginPage()で峺協しています。

2指朕のシ�`ケンスではhttp.oauth2Client()で或粥顎岳鞄2.0を佩うように峺協しています。http.oauth2Client()もhttp.oauth2Login()と揖��に、/oauth2/authorization/{registrationId}へのリダイレクトをトリガ�`にシ�`ケンスが蝕兵されます。http.oauth2Login()の�袁犬紛�恬については、參念��墮した仝Spring Security の児云とOIDC�J�^�rの�嘛�々を歌孚ください。
2指朕シ�`ケンスのregistrationIdはmicrosoftonline4rscですので、2指朕のシ�`ケンスを蝕兵するには、/oauth2/authorization/microsoftonline4rscへリダイレクトする駅勣があります。このリダイレクトする�I尖は徭念で�g廾する駅勣があります。http.addFilterAfter()にて、/oauth2/authorization/へリダイレクトするフィルタを、microsoftonline4rscAuthorizationFilterの朔ろに弖紗しています。
2指朕のシ�`ケンスを蝕兵するフィルタ
2指朕のシ�`ケンスを蝕兵するためのフィルタを�g廾します。
private Filter createStartAuthorazationFilter(HttpSecurity http, String registrationId) {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(
HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain
) throws ServletException, IOException {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// �J�^が頼阻したのか倦か
// �J�^が隆頼阻の��栽、`authentication`のクラスは `AnonymousAuthenticationToken` となります。
// �J�^が頼阻した��栽は、`OAuth2AuthenticationToken`になります。
// クラスの�`いで�J�^が頼阻したのか倦かを登僅しています。
if (authentication instanceof OAuth2AuthenticationToken) {
// �J辛�gみのクライアントを函誼します。
// もし、函誼できない��栽(authorizedClient == null)、まだアクセスト�`クンが函誼竃栖ていません。
OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(
registrationId,
authentication.getName()
);
if (authorizedClient == null) {
// `/oauth2/authorization/{registrationId}`へリダイレクトして、�J辛プロセスが畠て頼阻した瘁、
// 圷のペ�`ジ�╂���`/secure/user��`のパスにリダイレクトしてもらう駅勣があります。
// 參和のコ�`ドにより、Spring Securityに��して、圷のペ�`ジへのリクエスト秤�鵑魃3屬靴討�くことが竃栖ます。
RequestCache requestCache = http.getSharedObject(RequestCache.class);
requestCache.saveRequest(request, response);
// リダイレクト
AuthenticationEntryPoint entryPoint = new LoginUrlAuthenticationEntryPoint(
OAuth2AuthorizationRequestRedirectFilter.DEFAULT_AUTHORIZATION_REQUEST_BASE_URI + "/" + registrationId
);
entryPoint.commence(request, response, null);
} else {
filterChain.doFilter(request, response);
}
} else {
filterChain.doFilter(request, response);
}
}
};
}フィルタでは、範�^�gみ、かつ、徭念で喘吭したリソ�`スサ�`バ�`へのアクセスト�`クンが隆�k佩の魁栽、/oauth2/authorization/microsoftonline4rscへリダイレクトさせています。リダイレクトする縞は、リクエスト坪否を匯扮隠贋してから、リダイレクトするようにしています。
アクセスト�`クンを函誼する圭隈
アクセスト�`クンを函誼するコ�`ドです。
@Service
public class OAuth2TokenService {
@Autowired
private OAuth2AuthorizedClientService clientService;
public OAuth2AccessToken getAccessToken() {
return getAccessToken(null);
}
public OAuth2AccessToken getAccessToken(String registrationId) {
OAuth2AuthenticationToken authentication = (OAuth2AuthenticationToken) SecurityContextHolder
.getContext()
.getAuthentication();
OAuth2AuthorizedClient authorizedClient = clientService.loadAuthorizedClient(
registrationId == null ? authentication.getAuthorizedClientRegistrationId() : registrationId,
authentication.getName()
);
return authorizedClient.getAccessToken();
}
}clientService.loadAuthorizedClient(...)の及1哈方にregistrationIdを峺協することで、そのregistrationIdに��鬉靴織▲�セスト�`クンを函誼することが竃栖ます。なお、authentication.getAuthorizedClientRegistrationId()は範�^で聞喘されたregistrationIdを卦抜します。書指の箭で冱うとmicrosoftonlineになります。
おわりに
1指朕のシ�`ケンスから、2指朕のシ�`ケンスを�_兵させる圭隈が��つからず、寄蛍、逗�蕕靴泙靴拭�Spring Security�箸任Δ泙い海箸笋辰討�れないか�{べたのですが、いい圭隈が��つからず、�Y蕉はフィルタを弖紗する圭隈で鯛ち彭きました。ゴ�`ルに���dしたようなシ�`ケンス�蹐�ないと、Spring Securityのコ�`ドを�iみ盾くのは�yしいですね。
ではまた。
