Microsoft ID プラットフォ`ムのアクセスト`クンが ̄Invalid Signature ̄になる周 その2Spring 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指朕のシ`ケンスでは、OIDCJ^Graph API喘のアクセスト`クンをk佩してBいます。2指朕のシ`ケンスでは、OAuth2.0により徭念で喘吭したリソ`スサ`バ`へのアクセスト`クンをk佩してBいます。

或鴛禽遺範^に駅勣な秤烏を譜協する

或鴛禽遺範^で駅勣となる秤烏をapplication.propertiesに協吶します。

# 1指朕のシ`ケンスOIDCJ^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指朕のシ`ケンスOIDCJ^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で駅勣となる譜協として、microsoftonlinemicrosoftonline4rscの2つを協吶しました。もし、oauth2.loginPage()を福待すると、皆沿姻庄稼乙皆艶界顎姻庄岳霞はどちらの譜協で範^すれば措いのか登僅が竃栖ないため、參和の鮫中を燕幣してユ`ザ`に僉kさせる強恬となります。書指はmicrosoftonlineで或鴛禽遺範^したいので、oauth2.loginPage()で峺協しています。

2指朕のシ`ケンスではhttp.oauth2Client()で或粥顎岳鞄2.0を佩うように峺協しています。http.oauth2Client()http.oauth2Login()と揖に、/oauth2/authorization/{registrationId}へのリダイレクトをトリガ`にシ`ケンスが蝕兵されます。http.oauth2Login()の袁犬紛恬については、參念墮した仝Spring Security の児云とOIDCJ^rの嘛々を歌孚ください。

2指朕シ`ケンスのregistrationIdmicrosoftonline4rscですので、2指朕のシ`ケンスを蝕兵するには、/oauth2/authorization/microsoftonline4rscへリダイレクトする駅勣があります。このリダイレクトするI尖は徭念でg廾する駅勣があります。http.addFilterAfter()にて、/oauth2/authorization/microsoftonline4rscへリダイレクトするフィルタを、AuthorizationFilterの朔ろに弖紗しています。

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しいですね。

ではまた。


Recommendおすすめブログ