S SmartDocs
Série: Springboot java 95 lignes · Mis à jour 2026-08-14

AuthService.java

Springboot/bookstore-api/src/main/java/com/example/bookstore/service/AuthService.java

package com.example.bookstore.service;

import com.example.bookstore.dto.AuthResponse;
import com.example.bookstore.dto.LoginRequest;
import com.example.bookstore.dto.RegisterRequest;
import com.example.bookstore.dto.UserResponse;
import com.example.bookstore.entity.Role;
import com.example.bookstore.entity.User;
import com.example.bookstore.exception.DuplicateResourceException;
import com.example.bookstore.repository.UserRepository;
import com.example.bookstore.security.JwtService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 認證 Service:處理「註冊」與「登入」的商業邏輯。
 */
@Service
public class AuthService {

    private final UserRepository userRepository;
    private final PasswordEncoder passwordEncoder;
    private final AuthenticationManager authenticationManager;
    private final JwtService jwtService;

    public AuthService(UserRepository userRepository,
                       PasswordEncoder passwordEncoder,
                       AuthenticationManager authenticationManager,
                       JwtService jwtService) {
        this.userRepository = userRepository;
        this.passwordEncoder = passwordEncoder;
        this.authenticationManager = authenticationManager;
        this.jwtService = jwtService;
    }

    /**
     * 註冊新使用者。
     * 流程:檢查重複 → 密碼加密 → 存入資料庫 → 回傳使用者資料(不含密碼)
     */
    @Transactional
    public UserResponse register(RegisterRequest request) {

        // 1. 檢查帳號與 Email 是否已被使用(重複則回 409 Conflict)
        if (userRepository.existsByUsername(request.username())) {
            throw new DuplicateResourceException("帳號已被使用:" + request.username());
        }
        if (userRepository.existsByEmail(request.email())) {
            throw new DuplicateResourceException("Email 已被使用:" + request.email());
        }

        // 2. 建立使用者:密碼務必先用 BCrypt 加密再儲存!
        //    passwordEncoder.encode() 每次都會產生不同的雜湊值(自動加鹽)
        User user = new User(
                request.username(),
                passwordEncoder.encode(request.password()),
                request.email(),
                Role.ROLE_USER   // 新註冊者一律是一般使用者(安全預設)
        );

        // 3. 存入資料庫並回傳(UserResponse 不包含密碼欄位)
        User saved = userRepository.save(user);
        return UserResponse.from(saved);
    }

    /**
     * 登入。
     * 流程:驗證帳號密碼 → 產生 JWT → 回傳 token 給客戶端
     */
    public AuthResponse login(LoginRequest request) {

        // 1. 把帳號密碼交給 AuthenticationManager 驗證。
        //    它會透過 CustomUserDetailsService 載入使用者、
        //    再用 BCrypt 比對密碼;驗證失敗會拋出 BadCredentialsException
        //    (由 GlobalExceptionHandler 統一轉成 401 回應)。
        authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                        request.username(), request.password()));

        // 2. 驗證通過 → 從資料庫取得完整使用者資料
        User user = userRepository.findByUsername(request.username())
                .orElseThrow();   // 前面已驗證成功,理論上必定存在

        // 3. 產生 JWT 並包裝成回應
        String token = jwtService.generateToken(user.getUsername(), user.getRole());
        return new AuthResponse(
                token,
                "Bearer",
                jwtService.getExpirationMs() / 1000,   // 毫秒轉成秒
                user.getUsername(),
                user.getRole().name());
    }
}

Articles liés

Springboot java EN Mis à jour 2026-08-14

BookstoreApiApplication.java

BookstoreApiApplication.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/BookstoreApiApplication.java).

Lire l'article →
Springboot java EN Mis à jour 2026-08-14

DataInitializer.java

DataInitializer.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/config/DataInitializer.java).

Lire l'article →
Springboot java EN Mis à jour 2026-08-14

SecurityConfig.java

SecurityConfig.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/config/SecurityConfig.java).

Lire l'article →
Springboot java EN Mis à jour 2026-08-14

AuthController.java

AuthController.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/controller/AuthController.java).

Lire l'article →
Springboot java EN Mis à jour 2026-08-14

BookController.java

BookController.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/controller/BookController.java).

Lire l'article →
Springboot java EN Mis à jour 2026-08-14

ApiErrorResponse.java

ApiErrorResponse.java — java source code from the Springboot learning materials (Springboot/bookstore-api/src/main/java/com/example/bookstore/dto/ApiErrorResponse.java).

Lire l'article →