You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot应用基于自定义Token的身份认证实现方案咨询

Alright, let's break down how to build this custom token-based authentication flow for your Spring Boot REST API. I’ve implemented this exact pattern a few times, so here’s a hands-on, step-by-step guide that fits your requirements:

Step-by-Step Implementation

1. Define Token Entity & Repository

First, create an entity to represent your custom auth token in the database, along with a repository to handle database operations:

@Entity
@Table(name = "auth_tokens")
public class AuthToken {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @Column(unique = true, nullable = false)
    private String token;
    
    @Column(nullable = false)
    private Long userId; // Link to your existing user entity
    
    @Column(nullable = false)
    private LocalDateTime expiryDate;
    
    // Getters, setters, and constructors
}
public interface AuthTokenRepository extends JpaRepository<AuthToken, Long> {
    // Find token by its string value for validation
    Optional<AuthToken> findByToken(String token);
}

2. Build a Token Validation Service

Create a service class to encapsulate token validation logic—this is where you'll check if the token exists in the DB and hasn't expired:

@Service
public class TokenService {
    private final AuthTokenRepository tokenRepository;

    // Constructor injection (preferred over @Autowired)
    public TokenService(AuthTokenRepository tokenRepository) {
        this.tokenRepository = tokenRepository;
    }

    public AuthToken validateToken(String token) {
        return tokenRepository.findByToken(token)
                // Check if token is still valid (not expired)
                .filter(authToken -> authToken.getExpiryDate().isAfter(LocalDateTime.now()))
                .orElseThrow(() -> new AuthenticationCredentialsNotFoundException("Invalid or expired auth token"));
    }
}

3. Custom Authentication Filter

Spring Security uses filters to handle auth, so we'll create a custom filter that extracts the token from incoming requests, validates it, and sets the authenticated user in the security context:

@Component
public class CustomTokenAuthenticationFilter extends OncePerRequestFilter {
    private final TokenService tokenService;

    public CustomTokenAuthenticationFilter(TokenService tokenService) {
        this.tokenService = tokenService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // Extract token from request header (adjust the header name to match what your frontend uses)
        String authToken = request.getHeader("X-Auth-Token");

        if (authToken != null && !authToken.isBlank()) {
            try {
                // Validate the token against the database
                AuthToken validToken = tokenService.validateToken(authToken);
                
                // Create a UserDetails object (customize this to match your actual user model)
                UserDetails userDetails = User.withUsername(validToken.getUserId().toString())
                        .password("") // Password isn't needed here since we're using token-based auth
                        .authorities("ROLE_USER") // Add your user's roles/permissions here
                        .build();
                
                // Create an authentication token and set it in the security context
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities()
                );
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                
                SecurityContextHolder.getContext().setAuthentication(authentication);
            } catch (AuthenticationException e) {
                // Clear context and return 401 if token is invalid
                SecurityContextHolder.clearContext();
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getMessage());
                return;
            }
        }

        // Continue with the rest of the filter chain
        filterChain.doFilter(request, response);
    }
}

4. Configure Spring Security

Wire up your custom filter into the Spring Security chain, define public/private endpoints, and handle auth exceptions:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    private final CustomTokenAuthenticationFilter customTokenFilter;

    public SecurityConfig(CustomTokenAuthenticationFilter customTokenFilter) {
        this.customTokenFilter = customTokenFilter;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                // Disable CSRF since we're building a REST API (not form-based)
                .csrf(csrf -> csrf.disable())
                // Define authorization rules
                .authorizeHttpRequests(auth -> auth
                        .requestMatchers("/api/public/**").permitAll() // Allow public access to these endpoints (e.g., login, register)
                        .anyRequest().authenticated() // All other endpoints require valid auth
                )
                // Add our custom filter BEFORE the default username/password filter
                .addFilterBefore(customTokenFilter, UsernamePasswordAuthenticationFilter.class)
                // Handle auth errors (return 401 for missing/invalid tokens)
                .exceptionHandling(ex -> ex
                        .authenticationEntryPoint((request, response, authException) -> {
                            response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized: Missing or invalid auth token");
                        })
                );

        return http.build();
    }
}
Additional Best Practices
  • Token Refresh Mechanism: Add a refresh token flow so users don't have to re-login frequently. Store refresh tokens in the DB with longer expiry, and let users exchange a valid refresh token for a new access token.
  • Database Optimization: Add a unique index on the token column in your auth_tokens table to speed up lookup queries—this is crucial since every authenticated request will hit this query.
  • Security Hardening:
    • Use HTTPS to prevent token interception during transit.
    • Store tokens in HttpOnly cookies on the frontend instead of local storage to reduce XSS attack risks.
    • Generate long, random tokens (use UUID.randomUUID().toString() or a secure token generator) to make brute-force attacks harder.
    • Set short expiry times for access tokens (e.g., 15-30 minutes) to limit the impact of a leaked token.

内容的提问来源于stack exchange,提问作者Shubham Rana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 09:19:04