Spring Security入門

# Spring Security入門

## はじめに

Spring Securityは、Spring Frameworkベースのアプリケーションに認証・認可の機能を提供するフレームワークです。この記事では、Spring Securityの基本的な設定と使用方法について解説します。

## 基本的な設定

### 1. 依存関係の追加

```xml
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
```

### 2. 基本的なセキュリティ設定

```java
@Configuration
@EnableWebSecurity
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .requestMatchers("/admin/**").hasRole("ADMIN")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .defaultSuccessUrl("/dashboard")
                .permitAll()
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/login?logout")
                .permitAll()
            );
            
        return http.build();
    }
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
```

## 認証の実装

### 1. ユーザーサービスの実装

```java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    
    @Autowired
    private UserRepository userRepository;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
            .orElseThrow(() -> new UsernameNotFoundException("ユーザーが見つかりません: " + username));
            
        return org.springframework.security.core.userdetails.User
            .withUsername(user.getUsername())
            .password(user.getPassword())
            .roles(user.getRoles().toArray(new String[0]))
            .build();
    }
}
```

### 2. ユーザーエンティティの定義

```java
@Entity
@Table(name = "users")
public class User {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true)
    private String username;
    
    private String password;
    
    @ElementCollection(fetch = FetchType.EAGER)
    private Set<String> roles = new HashSet<>();
    
    // getters and setters
}
```

## 認可の実装

### 1. メソッドレベルのセキュリティ

```java
@Service
public class UserService {
    
    @PreAuthorize("hasRole('ADMIN')")
    public void deleteUser(Long userId) {
        // ユーザー削除処理
    }
    
    @PreAuthorize("hasRole('USER')")
    public User getCurrentUser() {
        // 現在のユーザー情報取得
    }
}
```

### 2. コントローラーレベルのセキュリティ

```java
@RestController
@RequestMapping("/api/users")
public class UserController {
    
    @GetMapping("/profile")
    @PreAuthorize("isAuthenticated()")
    public UserProfile getProfile() {
        // プロフィール情報の取得
    }
    
    @PostMapping("/admin")
    @PreAuthorize("hasRole('ADMIN')")
    public void adminOperation() {
        // 管理者操作
    }
}
```

## セキュリティの基本機能

### 1. パスワードエンコーディング

```java
@Service
public class UserRegistrationService {
    
    @Autowired
    private PasswordEncoder passwordEncoder;
    
    public void registerUser(UserRegistrationDto dto) {
        User user = new User();
        user.setUsername(dto.getUsername());
        user.setPassword(passwordEncoder.encode(dto.getPassword()));
        user.setRoles(Collections.singleton("USER"));
        userRepository.save(user);
    }
}
```

### 2. CSRF保護

```java
@Configuration
public class SecurityConfig {
    
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .csrf(csrf -> csrf
                .ignoringRequestMatchers("/api/**")  // APIエンドポイントではCSRF保護を無効化
                .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
            );
        return http.build();
    }
}
```

## セキュリティのベストプラクティス

1. **パスワードの取り扱い**
   - 強力なパスワードエンコーダーの使用
   - パスワードのハッシュ化
   - ソルトの使用

2. **セッション管理**
   - セッションタイムアウトの設定
   - 同時ログインの制御
   - セッション固定攻撃への対策

3. **エラーハンドリング**
   - 適切なエラーメッセージ
   - ログイン失敗の制限
   - アカウントロックアウト

4. **セキュリティヘッダー**
   - XSS対策
   - クリックジャッキング対策
   - HSTSの設定

## 実装例：ログインフォーム

```html
<form th:action="@{/login}" method="post">
    <div>
        <label>ユーザー名:</label>
        <input type="text" name="username" required/>
    </div>
    <div>
        <label>パスワード:</label>
        <input type="password" name="password" required/>
    </div>
    <div>
        <input type="submit" value="ログイン"/>
    </div>
</form>
```

## まとめ

Spring Securityは、アプリケーションに強力なセキュリティ機能を提供します。適切な設定と実装により、安全なアプリケーションを構築することができます。

## 参考資料

- Spring Security公式ドキュメント
- OWASPセキュリティガイドライン
- Spring Boot Reference Guide