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

Spring Boot MVC应用集成JWT令牌实现登录认证求助

解决Spring Boot MVC自定义登录页返回JWT的问题

核心思路

MVC场景下的表单登录默认是登录成功后跳转页面,要返回JWT需自定义登录成功处理器,在用户认证通过后生成令牌,再根据业务需求选择传递方式:优先用Cookie存储(安全),也可返回JSON或通过URL参数传递(不推荐)。


1. 自定义登录成功处理器

创建CustomAuthenticationSuccessHandler类,实现AuthenticationSuccessHandler接口,在认证成功后生成JWT并处理传递逻辑:

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.SavedRequest;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class CustomAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    private final JwtTokenUtil jwtTokenUtil;

    public CustomAuthenticationSuccessHandler(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        // 获取登录用户信息,生成JWT
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        String jwtToken = jwtTokenUtil.generateToken(userDetails);

        // 方案1:将JWT存入HttpOnly Cookie(推荐,防XSS)
        Cookie jwtCookie = new Cookie("JWT_TOKEN", jwtToken);
        jwtCookie.setHttpOnly(true);
        jwtCookie.setSecure(true); // 生产环境开启,仅HTTPS传输
        jwtCookie.setPath("/");
        jwtCookie.setMaxAge(24 * 60 * 60); // 有效期1天
        response.addCookie(jwtCookie);

        // 跳转到登录前的目标页面或默认首页
        String targetUrl = request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST") != null
                ? ((SavedRequest) request.getSession().getAttribute("SPRING_SECURITY_SAVED_REQUEST")).getRedirectUrl()
                : "/dashboard";
        response.sendRedirect(targetUrl);

        // ------------------------------
        // 方案2:直接返回JSON令牌(适合前端需拿令牌发请求的场景)
        // response.setContentType("application/json");
        // response.getWriter().write("{\"token\":\"" + jwtToken + "\"}");
        // response.getWriter().flush();
    }
}

2. 配置Spring Security使用自定义处理器

在SecurityConfig中替换默认的登录成功处理器:

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.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    private final JwtTokenUtil jwtTokenUtil;

    public SecurityConfig(JwtTokenUtil jwtTokenUtil) {
        this.jwtTokenUtil = jwtTokenUtil;
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .antMatchers("/login", "/css/**", "/js/**").permitAll()
                .antMatchers("/students/**").hasRole("ADMIN")
                .antMatchers("/subjects/**").hasRole("USER")
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login") // 自定义登录页路径
                .loginProcessingUrl("/do-login") // 表单提交接口
                .successHandler(customAuthenticationSuccessHandler()) // 配置自定义处理器
                .failureUrl("/login?error=true")
                .permitAll()
            )
            .logout(logout -> logout
                .logoutSuccessUrl("/login?logout=true")
                .permitAll()
            );

        // 若需用JWT保护接口,添加JWT过滤器
        // http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public AuthenticationSuccessHandler customAuthenticationSuccessHandler() {
        return new CustomAuthenticationSuccessHandler(jwtTokenUtil);
    }
}

3. 页面中获取JWT(针对Cookie方案)

前端页面可通过JS读取Cookie,后续AJAX请求时在请求头携带令牌:

// 从Cookie中提取JWT
function getCookie(name) {
    let value = "; " + document.cookie;
    let parts = value.split("; " + name + "=");
    if (parts.length === 2) return parts.pop().split(";").shift();
}

// 发起带令牌的请求
function fetchStudents() {
    const token = getCookie('JWT_TOKEN');
    fetch('/students', {
        headers: {
            'Authorization': 'Bearer ' + token
        }
    })
    .then(response => response.json())
    .then(data => console.log(data));
}

注意事项

  • 确保JwtTokenUtil能生成包含用户权限的令牌,后续JWT过滤器需解析权限做授权判断
  • 生产环境必须开启Cookie的Secure和HttpOnly属性,提升安全性
  • 若用返回JSON的方案,需将登录表单改为AJAX提交,避免页面直接显示JSON内容

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:01:15