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

Spring Boot应用如何调用外部JWT认证接口实现跨微服务身份验证

双微服务认证流程实现方案

1. 微服务1(认证服务)适配调整

你已经有了基础的认证逻辑,只需补充2项配置即可适配调用:

  • 公开登录接口:在Spring Security配置类中将/auth/login(你的实际认证接口路径)设置为无需认证即可访问,示例配置片段:
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeHttpRequests(auth -> auth
            .requestMatchers("/auth/login").permitAll()
            .anyRequest().authenticated()
        );
    return http.build();
}
  • 接口返回规范:登录成功后返回结构包含access_token、expires_in两个核心字段即可,无需额外改造原有JWT签发逻辑。

2. 微服务2(Vaadin+Spring Security)核心实现

2.1 Spring Security基础配置

首先调整Spring Security规则,放行Vaadin静态资源、自定义登录页,禁用默认表单登录:

@Bean
public SecurityFilterChain vaadinSecurityFilterChain(HttpSecurity http) throws Exception {
    http.csrf().disable()
        .authorizeHttpRequests(auth -> auth
            // 放行Vaadin静态资源与登录页
            .requestMatchers("/login", "/VAADIN/**", "/frontend/**").permitAll()
            .anyRequest().authenticated()
        )
        // 禁用默认登录页,使用自定义Vaadin登录视图
        .formLogin().disable()
        .exceptionHandling(e -> e.authenticationEntryPoint(
            (request, response, authException) -> response.sendRedirect("/login")
        ));
    // 追加自定义JWT校验过滤器
    http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
    return http.build();
}

2.2 自定义Vaadin登录视图

使用Vaadin原生Login组件实现登录页,用户提交后调用认证服务接口拿JWT:

@Route("login")
@PageTitle("登录")
public class LoginView extends VerticalLayout {
    private final WebClient.Builder webClientBuilder;

    public LoginView(WebClient.Builder webClientBuilder) {
        this.webClientBuilder = webClientBuilder;
        setSizeFull();
        setAlignItems(Alignment.CENTER);
        setJustifyContentMode(JustifyContentMode.CENTER);

        Login login = new Login();
        login.addLoginListener(event -> {
            // 调用认证服务接口拿JWT
            try {
                Map<String, String> authResult = webClientBuilder.build()
                    .post()
                    .uri("http://你的认证服务部署地址/auth/login")
                    .bodyValue(Map.of(
                        "email", event.getUsername(),
                        "password", event.getPassword()
                    ))
                    .retrieve()
                    .bodyToMono(new ParameterizedTypeReference<Map<String, String>>() {})
                    .block();

                String jwt = authResult.get("access_token");
                // 把JWT存入当前Vaadin会话
                VaadinSession.getCurrent().setAttribute("jwt", jwt);
                // 构造认证信息存入Spring Security上下文,无自定义JWT认证类可直接用UsernamePasswordAuthenticationToken替换
                JwtAuthenticationToken authToken = new JwtAuthenticationToken(jwt, Collections.emptyList());
                SecurityContextHolder.getContext().setAuthentication(authToken);
                // 登录成功跳转到仪表盘
                UI.getCurrent().navigate(DashboardView.class);
            } catch (Exception e) {
                login.setError(true);
            }
        });
        add(login);
    }
}

2.3 实现JWT校验过滤器

确保后续所有请求都能校验JWT有效性,维持登录状态:

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    // 注入你的JWT工具类,负责校验JWT签名、有效期
    private final JwtUtils jwtUtils;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 从Vaadin会话拿JWT
        String jwt = (String) VaadinSession.getCurrent().getAttribute("jwt");
        if (jwt != null && jwtUtils.validateToken(jwt)) {
            // 提取用户信息构造认证对象
            String userId = jwtUtils.getUserIdFromJwt(jwt);
            JwtAuthenticationToken authToken = new JwtAuthenticationToken(jwt, Collections.emptyList());
            authToken.setAuthenticated(true);
            SecurityContextHolder.getContext().setAuthentication(authToken);
        }
        filterChain.doFilter(request, response);
    }
}

3. 可选优化项

  • JWT过期时自动清除会话信息,跳转到登录页
  • 调用其他后端接口时,从会话中取出JWT放到请求头Authorization: Bearer {jwt}中传递
  • 敏感操作全程使用HTTPS传输,避免密码、JWT泄露

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 21:27:02