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

JHipster Angular调用Spring后端Kafka Webflux接口401无Bearer令牌问题

问题根因

原生浏览器EventSource API 本身不支持自定义Authorization这类请求头,且它发出的所有请求不会经过Angular的HTTP拦截器链路,你为HttpClient配置的全局Bearer令牌注入逻辑对SSE请求完全不生效,这就是接口返回401的核心原因。

符合Angular依赖注入规范的两种解决方案

两种方案都可以直接复用JHipster自带的AuthServerProvider组件获取当前登录用户的令牌,不需要额外实现独立的HTTP客户端。

方案一:令牌拼入URL参数(改造成本最低)

后端适配支持从查询参数读取access_token做鉴权即可,前端改动极小:

  1. 先在MqconnectService中注入JHipster自带的AuthServerProvider获取令牌,把令牌拼到请求URL后
import { AuthServerProvider } from 'app/core/auth/auth-server-provider.service';

@Injectable({
  providedIn: 'root',
})
export class MqconnectService {
  url: string = KAFKA_CONSUME_MSG; 

  constructor(private authServerProvider: AuthServerProvider) {}

  getMessagesStream(): Observable<StandardMessage> {
    return new Observable<StandardMessage>(observer => {
      // 从JHipster自带的认证服务拿当前登录用户的令牌
      const token = this.authServerProvider.getToken();
      // 令牌拼入URL参数
      const urlWithToken = `${this.url}?access_token=${token}`;
      const eventSource = new EventSource(urlWithToken, {withCredentials: true});
      
      // 原有onmessage、onerror逻辑保持不变
      eventSource.onmessage = event => {
        console.debug('received event: ', event);
        const json = JSON.parse(event.data);
        observer.next(
          new StandardMessage(
            json['Id'],
            // OMITTED
          )
        );
      };
      eventSource.onerror = error => {
        if (eventSource.readyState === 0) {
          console.log('The stream has been closed by the server.');
          eventSource.close();
          observer.complete();
        } else {
          observer.error('EventSource error: ' + `${String(error)}`);
        }
      };
    });
  }
}
  1. 后端Spring Boot资源服务器适配,支持从参数读取令牌:
@Configuration
public class SecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.oauth2ResourceServer()
            .bearerTokenResolver(new DefaultBearerTokenResolver() {
                @Override
                public String resolve(HttpServletRequest request) {
                    // 优先从请求头取令牌,取不到再从查询参数取
                    String token = super.resolve(request);
                    if (token == null) {
                        token = request.getParameter("access_token");
                    }
                    return token;
                }
            });
        // 保留原有其他安全配置
        return http.build();
    }
}

方案二:用支持自定义头的SSE polyfill(安全性更高)

如果担心令牌出现在URL中会被日志记录泄露,可以使用兼容原生API的eventsource polyfill库,支持设置请求头,不需要修改后端鉴权逻辑:

  1. 安装依赖:npm install eventsource
  2. 前端改造代码:
import * as EventSource from 'eventsource';
import { AuthServerProvider } from 'app/core/auth/auth-server-provider.service';

@Injectable({
  providedIn: 'root',
})
export class MqconnectService {
  url: string = KAFKA_CONSUME_MSG; 

  constructor(private authServerProvider: AuthServerProvider) {}

  getMessagesStream(): Observable<StandardMessage> {
    return new Observable<StandardMessage>(observer => {
      const token = this.authServerProvider.getToken();
      // 自定义请求头塞入Bearer令牌
      const initOptions = {
        withCredentials: true,
        headers: {
          'Authorization': `Bearer ${token}`
        }
      };
      const eventSource = new EventSource(this.url, initOptions);
      // 原有业务逻辑保持不变
    });
  }
}

补充注意事项

如果SSE长连接期间令牌过期,后端会主动断开连接,你可以在onerror回调中判断返回状态为401时,复用JHipster自带的令牌刷新逻辑,拿到新令牌后自动重连即可,不需要额外改造认证体系。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.28 13:24:10