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
相关产品推荐
相关产品推荐

