スコープのトークンによるAPI実行


## 目次
- スコープについて
- API作成
- リソースサーバーの設定
- Keycloakでスコープを設定
- アクセストークンを発行する


## 参考サイト
- [KeycloakとSpringBoot/SecurityでOpenID Connect(リソースサーバー編)](https://qiita.com/kasa_le/items/259792d3ae4df7f1d2b2)

## スコープについて
- OpenID Connectではスコープを複数指定出来る。
- ユーザーの属性を任意でアクセストークンに含めることが出来る。
- スコープを使って、アクセス出来る/出来ないAPIが作ることが出来る。
- スコープ名には毛頭に「SCOPE_」が必要になる。

## API作成
以下のAPIを作成する。

|No|API Name|API path|Scope Name|Java File|解説|
|---|---|---|---|---|---|
|1|Permit all|/|-|PermitAllController.java|すべてのアクセスを許可|
|2|Special|/special|SCOPE_special|SpecialController.java|'special'スコープを持ったアクセストークンでのみアクセス可能|
|3|Get Object|/getObject|SCOPE_getObject|GetObjectController.java|'getObject'スコープを持ったアクセストークンでのみアクセス可能|

- PermitAllController.java

```
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class PermitAllController {

    @GetMapping("/")
    public String special() {
        return "Welcome!";
    }
}
```

- SpecialController.java

```
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SpecialController {

    @GetMapping("/special")
    public String special() {
        return "Special!";
    }
}
```
- GetObjectController.java

```
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.Arrays;
import java.util.List;

@RestController
public class GetObjectController {

    @GetMapping(path = "/getObject")
    public List<String> getObject() {
        return Arrays.asList("value1","value2","value3");
    }
}
```

## リソースサーバーの設定
- リソースサーバーに、スコープマッピングを設定する。

```
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(HttpMethod.GET, "/special").hasAuthority("SCOPE_special")
                .antMatchers(HttpMethod.GET, "/getObject").hasAuthority("SCOPE_getObject")
                .antMatchers(HttpMethod.GET, "/").permitAll()
                .anyRequest().authenticated();
        http.oauth2ResourceServer()
                .jwt();
    }
}
```

## Keycloakでスコープを設定
- 以下APIの為、specialとgetObjectのスコープを追加する必要がある。
- [Keycloakの操作について](https://qiita.com/nayylin/items/e9dd41d0cdf923c6d0c9) を参考し、「スコープ、マッパーの作成とクライアントにスコープを設定する」部分通りに行う。

|No|API Name|API path|Scope Name|
|---|---|---|---|
|1|Special|/special|SCOPE_special|
|2|Get Object|/getObject|SCOPE_getObject|

## API実行

|No|API Name|API path|アクセストークン発行は必要？|
|---|---|---|---|---|---|
|1|Permit all|/|必要ない|
|2|Special|/special|必要|
|3|Get Object|/getObject|必要|

### ①アクセストークンを発行する
Special APIのトークン発行の為、scopeに「openid {作成したスコープめい}」を追加し実行する。
※openidは必須
※Permit all APIは、アクセストークン発行は必要ない
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602725/2e3d74e6-6a2e-29a5-0bba-e3f08fe3c875.png)

レスポンス

```
{
    "access_token": "xxxxxxx",
    "expires_in": 300,
    "refresh_expires_in": 0,
    "token_type": "Bearer",
    "id_token": "xxxxx",
    "not-before-policy": 0,
    "scope": "openid profile email special"
}
```

### ②API実行する
SpecialとGet Object APIの場合は、①で取得したアクセストークンを利用し、APIを実行する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602725/29482c16-703e-8e1e-d132-7cbb517a338b.png)

Permit all APIは、そのまま実行する。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/602725/ceaa7214-3e44-12a1-06cc-90c6bf8b25cb.png)