初心者向けREST APIの認証を解説!Springで学ぶBasic認証とToken認証の基本
新人
「REST APIってよく聞くんですけど、そもそも何のことなんですか?」
先輩
「REST APIは、サーバーとクライアントがデータをやり取りするためのルールや仕組みの一種だよ。たとえば、ブラウザでWebページを見るのと同じように、アプリ同士が情報をやり取りする感じかな。」
新人
「なるほど……。でも、なんで認証とかが必要になるんですか?」
先輩
「REST APIは、ログイン機能のあるアプリや、機密情報を扱うサービスにも使われるから、不正なアクセスを防ぐために認証が重要なんだ。SpringではBasic認証やToken認証といった仕組みで守ることができるよ。」
新人
「SpringでREST APIを作るなら、そういう認証の仕組みも理解しておかないといけないってことですね!」
先輩
「うん、まずはREST APIとは何かから順番に見ていこうか。」
1. REST APIとは何か
REST APIとは、「Representational State Transfer」という設計思想に基づいたWeb APIのことです。URLやHTTPメソッド(GET、POST、PUT、DELETEなど)を使って、サーバーのリソース(データ)にアクセスする方式です。Springでは、@Controllerと@RequestMappingなどを使って、REST APIを簡単に実装できます。
たとえば、SpringでGETリクエストを処理する簡単なAPIは以下のように書けます。
@Controller
public class SampleController {
@ResponseBody
@RequestMapping(value = "/hello", method = RequestMethod.GET)
public String hello() {
return "こんにちは、REST APIの世界へようこそ!";
}
}
この例では、/helloというURLにGETリクエストを送ると、文字列が返ってきます。これはREST APIのごく基本的な使い方で、Springの初心者向け教材としてもよく使われます。
2. なぜ認証が必要なのか
REST APIはインターネットを通じて外部からアクセスされることが多いため、セキュリティ対策がとても重要です。たとえば、銀行のアプリやECサイトの管理画面などで、認証なしにデータにアクセスできてしまったら、情報漏洩や不正利用のリスクが生じます。
そのため、REST APIではアクセス制限をかけるための「認証(Authentication)」という仕組みを導入します。Springでは、代表的な認証方式として次のようなものが利用できます。
Basic認証
Basic認証は、もっともシンプルな認証方式で、ユーザー名とパスワードをHTTPヘッダに付与して送信する方法です。Springでは設定ファイルとSecurityFilterChainを使って実装します。
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authz -> authz
.anyRequest().authenticated()
)
.httpBasic(); // Basic認証を有効化
return http.build();
}
@Bean
public UserDetailsService users() {
UserDetails user = User.builder()
.username("user")
.password("{noop}password") // プレーンテキスト(実際の開発では暗号化を推奨)
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
この設定を行うことで、すべてのリクエストに対してユーザー名とパスワードによるBasic認証が必要になります。
Token認証
Token認証は、ログイン時に発行されたトークンを使ってAPIにアクセスする方式です。トークンは通常、HTTPヘッダに含めて送信します。Basic認証に比べてセキュリティや柔軟性が高く、実際のアプリ開発でよく利用されます。
簡易的なToken認証の例として、リクエストヘッダにAuthorizationを付けてチェックする方法を見てみましょう。
@Controller
public class TokenController {
private static final String VALID_TOKEN = "abc123token";
@ResponseBody
@RequestMapping(value = "/secure-data", method = RequestMethod.GET)
public ResponseEntity<String> secureEndpoint(@RequestHeader("Authorization") String authHeader) {
if (authHeader != null && authHeader.equals("Bearer " + VALID_TOKEN)) {
return ResponseEntity.ok("認証成功!安全なデータです。");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("認証エラー:無効なトークンです。");
}
}
}
この例では、事前に決めたabc123tokenというトークンを使って、特定のエンドポイントにアクセスできるようになっています。実際のシステムではトークンの有効期限や署名検証など、より高度な処理が行われます。
Spring Securityとの連携
Springでは、Spring Securityという強力なセキュリティ機能を使って、認証・認可の仕組みを柔軟に実装できます。Basic認証やToken認証を組み合わせて使うことも可能で、認可(Authorization)によるアクセス制限やロール管理も行えます。
特にSpringを使ったREST API開発では、@Controller構成でもSpring Securityの仕組みがそのまま使えるため、初心者でもセキュアな認証機能を簡単に追加できます。
今後は、JWT(JSON Web Token)などを使った認証方式も取り上げていく予定ですが、まずは今回のBasic認証とToken認証の基本をしっかり理解しておくことが、REST APIのセキュリティ対策の第一歩になります。
3. Basic認証の仕組みとSpringでの実装方法
Basic認証は、ユーザー名とパスワードを組み合わせて、毎回のリクエストごとに送信するシンプルな認証方式です。クライアントはHTTPリクエストのヘッダーにAuthorizationという項目を含めて、ログイン情報を送ります。
たとえば、「user:password」という文字列をBase64でエンコードし、それをAuthorization: Basic dXNlcjpwYXNzd29yZA==のようにヘッダーに付けます。この認証情報は暗号化されずに送られるため、SSL(HTTPS)通信と組み合わせて使用することが推奨されます。
SpringでBasic認証を使うためには、まずSpring Securityの依存関係をGradleで追加する必要があります。PleiadesのGradle設定画面からチェックを入れて追加できますが、build.gradleファイルに手動で追加する場合は以下のように記述します。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
その後、SecurityConfigクラスでBasic認証を有効化し、認証対象のURLを設定します。以下に基本的なコードを示します。
@Configuration
@EnableWebSecurity
public class BasicAuthSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.anyRequest().authenticated()
)
.httpBasic();
return http.build();
}
@Bean
public UserDetailsService userDetailsService() {
UserDetails user = User.builder()
.username("testuser")
.password("{noop}testpass")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(user);
}
}
{noop}はパスワードをそのまま扱う設定ですが、実際にはハッシュ化したパスワードを使うことが推奨されます。以上の設定で、/helloなどのエンドポイントにアクセスすると、ブラウザやツールから認証ダイアログが表示されます。
4. Token認証の仕組み(Bearerトークン)と使い分け
Token認証は、ログイン後にトークンを発行し、それをHTTPヘッダーに付与してAPIにアクセスする認証方式です。Springではこのようなトークン方式を自作することもできますし、JWTなどの外部ライブラリと組み合わせて実装することも可能です。
Bearerトークンとは、トークンをAuthorizationヘッダーに「Bearer トークン値」の形式で送る方式です。リクエスト例は次のようになります。
GET /secure-data HTTP/1.1
Authorization: Bearer abc123token
このBearerトークンをチェックするには、@RequestHeaderアノテーションを使ってヘッダーの内容を取り出し、値を検証します。以下は簡易的な実装例です。
@Controller
public class AuthTokenController {
private static final String TOKEN = "secure-token-123";
@ResponseBody
@RequestMapping(value = "/api/private", method = RequestMethod.GET)
public ResponseEntity<String> checkToken(@RequestHeader(value = "Authorization", required = false) String auth) {
if (auth != null && auth.equals("Bearer " + TOKEN)) {
return ResponseEntity.ok("トークン認証成功:データ取得可能");
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("認証エラー:無効なトークン");
}
}
}
この方式では、クライアント側がトークンを管理し、必要なときにだけリクエストに付与します。トークンの保存場所は、Webアプリならローカルストレージ、モバイルならセキュアストレージが一般的です。
Basic認証との違いは、ログイン情報を毎回送らない点です。セキュリティの観点では、Token認証のほうが安全性が高く、ユーザーごとの有効期限や権限の管理がしやすいというメリットがあります。
5. 実装に必要なSpring Securityの設定(Gradle・Javaコード)
Springで認証方式を実装するためには、Spring Securityの設定が欠かせません。初心者の方でも理解しやすいように、GradleとJavaコードそれぞれに分けて説明します。
Gradleの設定
Pleiadesの[Gradle]タブから「spring-boot-starter-security」にチェックを入れると、自動で設定されます。手動で行う場合は、build.gradleファイルのdependenciesに以下を追加します。
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-security'
}
依存関係を追加したら、プロジェクトを再ビルドして適用させます。
Javaコードでの設定
Spring Securityでは、フィルタチェーンやユーザー情報などをJavaコードで定義します。以下はToken認証とBasic認証を切り替えて試す際に参考になる構成です。
@Configuration
@EnableWebSecurity
public class CombinedSecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(auth -> auth
.antMatchers("/api/private").authenticated()
.anyRequest().permitAll()
)
.httpBasic(); // Basic認証を有効化
return http.build();
}
@Bean
public UserDetailsService customUserService() {
UserDetails user = User.builder()
.username("admin")
.password("{noop}admin123")
.roles("ADMIN")
.build();
return new InMemoryUserDetailsManager(user);
}
}
この設定により、/api/privateにアクセスするにはBasic認証が必要になります。Token認証を追加する場合は、OncePerRequestFilterなどのカスタムフィルターを使って、ヘッダーのトークンを検証する仕組みを構築できますが、初心者の段階では基本の理解を優先しましょう。
Springの設定は自由度が高いため、Basic認証とToken認証のどちらを使うかは、用途やセキュリティ要件によって選択するとよいでしょう。
6. 実務での認証方式の使い分け(シンプルなアプリとセキュアなアプリの違い)
実際の開発現場では、アプリケーションの規模や性質によって使う認証方式を選ぶことが大切です。認証はセキュリティの基盤となるため、適切に設計しないと重大な情報漏洩につながる可能性があります。
たとえば、社内向けのツールや一時的な簡易アプリであれば、Basic認証を用いることもあります。実装がシンプルで設定も容易なため、最小限の認証機能を手早く用意したい場面では有効です。ただし、通信は必ずHTTPSで行うようにしましょう。
一方、一般ユーザー向けのWebサービスやモバイルアプリでは、Token認証(特にJWTなど)を使うのが一般的です。理由は、次のような特徴があるためです。
- トークンに有効期限を設定できる
- ユーザー情報やロールを含められる
- ログイン状態をセッションレスで維持できる
たとえば、複数のフロントエンドアプリから同じバックエンドAPIにアクセスする場合、Token認証のほうが相性が良いです。マイクロサービス構成や外部連携のあるシステムでは、Tokenベースの認証方式が推奨されます。
7. 認証方式を使う上での注意点(セキュリティ上の落とし穴)
認証方式を正しく設定しても、セキュリティ対策が不十分だと攻撃の対象になります。初心者向けに、特に注意すべきポイントを以下に紹介します。
平文パスワードを使わない
{noop}を使ったプレーンテキストのパスワードは、テスト用途としては便利ですが、本番環境では絶対に使わないようにしましょう。SpringではBCryptなどのハッシュアルゴリズムを使ったパスワード暗号化が可能です。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
ハッシュ化されたパスワードを保存することで、万が一データベースが漏洩した場合でも情報の悪用を防げます。
トークンの漏洩リスクに備える
Token認証を使う場合、トークン自体が「鍵」となるため、これが盗まれると誰でもAPIにアクセスできてしまいます。そのため、以下の対策が重要です。
- トークンは
HTTPS経由でのみ通信させる - 一定時間でトークンを失効させる
- 重要な操作には二段階認証や再認証を行う
CORSの設定ミスによる情報漏洩
フロントエンドとバックエンドが別ドメインの場合、CORSの設定が必要です。設定を甘くすると、悪意あるドメインからAPIを呼び出される可能性があります。
@Bean
public WebMvcConfigurer corsConfigurer() {
return new WebMvcConfigurer() {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("https://example.com")
.allowedMethods("GET", "POST", "PUT", "DELETE");
}
};
}
許可するドメインは必要最小限に絞るのがポイントです。
8. 認証付きAPI設計のベストプラクティス(DTOの設計、レスポンス制御など)
REST APIの設計では、認証だけでなく、レスポンスの内容やデータ構造の設計も重要です。ここではSpringでの開発を前提に、初心者向けの実装ポイントをいくつか紹介します。
DTOクラスで必要なデータだけを受け渡す
エンティティ(Entity)そのままではなく、DTO(Data Transfer Object)クラスを使うことで、必要な項目だけを送受信できます。これにより、パスワードなどの重要情報を誤ってクライアントに返すミスを防げます。
public class UserDto {
private String username;
private String email;
// Getter / Setter
}
APIでは、このDTOクラスを使ってレスポンスを返すようにします。
@Controller
public class UserController {
@ResponseBody
@RequestMapping(value = "/user/info", method = RequestMethod.GET)
public ResponseEntity<UserDto> getUserInfo() {
UserDto dto = new UserDto();
dto.setUsername("user001");
dto.setEmail("user@example.com");
return ResponseEntity.ok(dto);
}
}
HTTPステータスコードの適切な利用
認証やエラー時には、意味のあるHTTPステータスコードを返すようにしましょう。たとえば、トークンが不正な場合は401 Unauthorized、アクセス権限がない場合は403 Forbiddenを返します。
レスポンスメッセージに注意
エラーメッセージに過度な情報を含めないようにしましょう。たとえば、「ユーザー名は存在するがパスワードが違う」といった表現は避け、「認証に失敗しました」など曖昧な表現が好まれます。
ログ出力と監視
認証に失敗したリクエストや不正なトークンアクセスは、ログに記録して監視することで、攻撃の兆候を早期に検知できます。SpringではLoggerを使ってログ出力が可能です。
private static final Logger logger = LoggerFactory.getLogger(TokenController.class);
logger.warn("無効なトークンが使用されました: " + authHeader);
開発中でも、セキュリティイベントはしっかりと記録しておくことが重要です。