Spring Boot + Auth0 でシンプルな認証・認可 (RBAC) を実装する


はじめに

本投稿では Auth0 の ID Token と Spring Boot にて RBAC を実現する方法を記述する。

実現方法

MP-JWT を模倣し、ID Token に権限情報をカスタムクレームとして付与する。

Auth0 の ID Token に権限情報を付与

Auth0 の ID Token には権限情報が付与されない。
ただし、カスタムクレームで権限情報を ID Token に付加できる。

Auth0 に User、Role、Permissions を設定

Auth0 ドキュメント に従い、Auth0 ユーザーに権限情報を設定する。
Access Token は使用しないため、Access token への権限情報の許可等の設定は不要。

Auth0 の ID Token にカスタムクレームを定義

Auth0 のダッシュボードで Rules を開き、ID Token へのカスタムクレーム追加のルールを定義する。
カスタムクレーム名は URL 形式の文字列とする制約がある。
本例では http://example.com/permissions とする。

Rule.js
function (user, context, callback) {
  var map = require('array-map');
  var ManagementClient = require('[email protected]').ManagementClient;
  var management = new ManagementClient({
    token: auth0.accessToken,
    domain: auth0.domain
  });

  var params = { id: user.user_id, page: 0, per_page: 50, include_totals: true };
  management.getUserPermissions(params, function (err, permissions) {
    if (err) {
      // Handle error.
      console.log('err: ', err);
      callback(err);
    } else {
      var permissionsArr = map(permissions.permissions, function (permission) {
        return permission.permission_name;
      });
      context.idToken['http://example.com/permissions'] = permissionsArr;
    }
    callback(null, user, context);
  });
}

ID Token の権限情報に基づき、Spring Security でアクセス制御する

以下、カスタムクレームに付加した認可情報を ID Token から取得し、アクセス制御に利用する Spring Boot アプリのセキュリティ設定サンプル。

Spring Boot アプリケーションの作成

Spring Initializer で以下の依存関係を選択してプロジェクトを作成する。

  • Spring Web
  • OAuth2 Resource Server Maven だと以下となる。
pom.xml
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
    </dependency>
</dependencies>

JWT 認証サーバ設定

認証サーバの設定はプロパティのみで行える。
Spring Security で定義された以下をの属性を設定する。

属性 設定値
spring.security.oauth2.resourceserver.jwt.issuer-uri https:// プレフィックスと / サフィックスが付いた Auth0 ドメイン。末尾 / を省略すると動かない。
auth0.audience Auth0 Application の Client ID。
application.properties
spring.security.oauth2.resourceserver.jwt.issuer-uri=https://YOUR_DOMAIN/
auth0.audience=YOUR_APP_CLIENT_ID

カスタムクレームの取得設定

ID Token のカスタムクレームに付加した権限情報を取得し、Security Principal に設定する。

application.properties
#Auth0 の Rules で定義したカスタムクレーム名
permissions.claim=http://example.com/permissions
SecurityConfig.java
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value(value = "${permissions.claim}")
    private String permissionsClaim;

    @Override
    public void configure(HttpSecurity http) throws Exception {

        http.authorizeRequests()
                .mvcMatchers("/api/public").permitAll()
                .mvcMatchers("/api/private").authenticated()
                .mvcMatchers("/api/private-scoped").hasAuthority("read:messages")
                .and().oauth2ResourceServer().jwt()
                .jwtAuthenticationConverter(jwt -> new JwtAuthenticationToken(jwt,
                        jwt.getClaimAsStringList(permissionsClaim)
                                .stream()
                                .map(SimpleGrantedAuthority::new)
                                .collect(Collectors.toList())));
    }
}

後は Controller を実装すれば Auth0 で設定した権限情報に基づいてアクセス制御が行える。
ID Token は Principal からアクセスできる。(実装クラスは上記例のとおり JwtAuthenticationToken )

参考

本投稿では以下の資料を参考にした。