認証と認可
データベースを使ったユーザー認証を設定し、さまざまなロールやパスに対するアクセス制御ルールを定義します。
「認証と認可」はCoddyKit上の無料Spring Boot 4 Complete Guideレッスンです。 これはレッスン2/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはSpring Boot 4 Complete Guide学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Spring Boot 4 Complete Guideコースには全4レッスンが含まれています。
このレッスンの一部はまだ翻訳されておらず、英語で表示されています。
AuthN vs. AuthZ
In security, we often talk about two key concepts: Authentication and Authorization.
- Authentication (AuthN) is about verifying who you are. Think of it like showing your ID to prove your identity.
- Authorization (AuthZ) is about determining what you are allowed to do once your identity is confirmed. This is like your ID granting you access to certain areas.
Database Auth Flow
Spring Security can use user details stored in a database to authenticate users. Instead of hardcoding users, we can connect to a real data source.
The process typically involves:
- A user attempts to log in.
- Spring Security fetches user details (username, password, roles) from your database.
- It verifies the password.
- If successful, the user is authenticated.
Fetching User Details
The core interface for retrieving user-specific data in Spring Security is UserDetailsService. You'll implement this to tell Spring how to find users in your database.
It has one method: loadUserByUsername(String username). This method returns a UserDetails object, which holds the user's username, password, and authorities (roles).
Custom UserDetailsService
Let's create a simple UserDetailsService. For now, we'll simulate fetching users from a list, but in a real app, this would query a database.
Notice we return a User object, which is a common implementation of UserDetails.
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@Service
public class MyUserDetailsService implements UserDetailsService {
private final Map<String, UserDetails> users = new HashMap<>();
public MyUserDetailsService(PasswordEncoder passwordEncoder) {
// Simulate users from a database
users.put("user", User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build());
users.put("admin", User.builder()
.username("admin")
.password(passwordEncoder.encode("adminpass"))
.roles("ADMIN", "USER")
.build());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = users.get(username);
if (user == null) {
throw new UsernameNotFoundException("User not found: " + username);
}
return user;
}
}Securing Passwords
Storing passwords as plain text is a major security risk. Spring Security requires you to use a PasswordEncoder to securely hash (encode) passwords.
The most common implementation is BCryptPasswordEncoder, which uses a strong hashing algorithm. You'll define this as a Spring bean.
Wiring Up Authentication
Now, let's wire our UserDetailsService and PasswordEncoder into Spring Security's configuration. We'll define a SecurityFilterChain bean.
This filter chain tells Spring how to handle requests, including authentication.
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
public class SecurityConfig {
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable()) // Disable CSRF for simplicity in this example
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated() // All other requests require authentication
)
.formLogin(form -> form.permitAll()); // Enable form login for browser access
return http.build();
}
}Full Auth Demo
Here's a complete Spring Boot application demonstrating basic authentication using our custom UserDetailsService and PasswordEncoder. Try accessing /hello after logging in!
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class AuthApp {
public static void main(String[] args) {
SpringApplication.run(AuthApp.class, args);
}
}
@RestController
class HelloController {
@GetMapping("/hello")
public String hello() {
return "Hello, authenticated user!";
}
}
@Service
class MyUserDetailsService implements UserDetailsService {
private final Map<String, UserDetails> users = new HashMap<>();
public MyUserDetailsService(PasswordEncoder passwordEncoder) {
users.put("user", User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build());
users.put("admin", User.builder()
.username("admin")
.password(passwordEncoder.encode("adminpass"))
.roles("ADMIN", "USER")
.build());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = users.get(username);
if (user == null) {
throw new UsernameNotFoundException("User not found: " + username);
}
return user;
}
}
@Configuration
@EnableWebSecurity
class SecurityConfig {
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(form -> form.permitAll());
return http.build();
}
}What You Can Do
Once a user is authenticated, authorization determines what resources or actions they are permitted to access. This is done by checking their assigned roles or authorities.
For example, an "ADMIN" user might access admin pages, while a "USER" user can only see their profile.
Securing Paths by Role
Spring Security allows you to define authorization rules directly in your SecurityFilterChain. You can protect specific URL patterns based on roles.
Key methods:
.requestMatchers("/admin/**").hasRole("ADMIN"): Only users with the 'ADMIN' role can access URLs under/admin/..requestMatchers("/user/**").hasAnyRole("USER", "ADMIN"): Users with 'USER' or 'ADMIN' role..anyRequest().authenticated(): All other requests need any authenticated user.
AuthZ in Action
Let's add authorization rules to our previous example. Try logging in as 'user' (password: 'password') and 'admin' (password: 'adminpass') and access the different endpoints.
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
@SpringBootApplication
public class AuthZApp {
public static void main(String[] args) {
SpringApplication.run(AuthZApp.class, args);
}
}
@RestController
class SecuredController {
@GetMapping("/public")
public String publicPage() {
return "This is a public page.";
}
@GetMapping("/user/profile")
public String userProfile() {
return "Welcome, user! This is your profile.";
}
@GetMapping("/admin/dashboard")
public String adminDashboard() {
return "Welcome, admin! This is the admin dashboard.";
}
}
@Service
class MyUserDetailsService implements UserDetailsService {
private final Map<String, UserDetails> users = new HashMap<>();
public MyUserDetailsService(PasswordEncoder passwordEncoder) {
users.put("user", User.builder()
.username("user")
.password(passwordEncoder.encode("password"))
.roles("USER")
.build());
users.put("admin", User.builder()
.username("admin")
.password(passwordEncoder.encode("adminpass"))
.roles("ADMIN", "USER")
.build());
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails user = users.get(username);
if (user == null) {
throw new UsernameNotFoundException("User not found: " + username);
}
return user;
}
}
@Configuration
@EnableWebSecurity
class SecurityConfig {
private final UserDetailsService userDetailsService;
public SecurityConfig(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
http
.csrf(csrf -> csrf.disable())
.authorizeHttpRequests(authorize -> authorize
.requestMatchers("/public").permitAll() // Public access
.requestMatchers("/user/**").hasRole("USER") // Only USER role
.requestMatchers("/admin/**").hasRole("ADMIN") // Only ADMIN role
.anyRequest().authenticated() // All others need authentication
)
.formLogin(form -> form.permitAll());
return http.build();
}
}Quick Check
Review the concepts of authentication and authorization, and the components involved.
Recap & Next Steps
Great job! In this lesson, you learned to:
- Distinguish between Authentication and Authorization.
- Understand how Spring Security uses databases for authentication.
- Implement a custom
UserDetailsServiceto fetch user data. - Use
PasswordEncoderto secure user passwords. - Configure URL-based authorization rules using roles.
Next, you'll explore more advanced security features like JWT-based authentication for stateless APIs!
よくある質問
「認証と認可」レッスンは無料ですか?
はい。「認証と認可」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Spring Boot 4 Complete Guideコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Spring Boot 4 Complete Guideコースには全4レッスンが含まれています。
「認証と認可」で何を学びますか?
データベースを使ったユーザー認証を設定し、さまざまなロールやパスに対するアクセス制御ルールを定義します。 ブラウザで直接実行するハンズオンコードでSpring Boot 4 Complete Guideを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Spring Boot 4 Complete Guideを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのSpring Boot 4 Complete Guideは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン2/4です。
「認証と認可」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このSpring Boot 4 Complete Guideレッスンでコードを書いて実行できますか?
はい。すべてのSpring Boot 4 Complete Guideレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。