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

Angular 5调用Spring+Shiro后端接口时会话不一致问题求助

解决Angular 5调用Spring+Shiro接口时JSESSIONID无法保持的问题

这个问题我之前帮同事排查过!核心原因就是跨域请求下Angular默认不会自动携带Cookie,而Postman会自动帮你带上会话Cookie,所以导致每次请求后端都认为是新会话,生成新的JSESSIONID。下面给你一步步解决的方案:

一、后端配置允许跨域携带凭证

首先要在Spring后端配置CORS,明确允许前端携带Cookie(凭证),同时注意allowedOrigins不能设为*,必须指定具体的前端域名/端口:

方式1:全局CORS配置

创建一个配置类,全局设置跨域规则:

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                // 替换成你的Angular前端地址,比如http://localhost:4200
                .allowedOrigins("http://localhost:4200")
                .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
                .allowedHeaders("*")
                // 关键:允许携带凭证(Cookie)
                .allowCredentials(true)
                .maxAge(3600);
    }
}

方式2:接口级别的@CrossOrigin注解

如果不想全局配置,也可以在单个Controller或接口上添加注解:

@RestController
@RequestMapping("/api")
// 同样要指定具体 origin 和 allowCredentials
@CrossOrigin(origins = "http://localhost:4200", allowCredentials = "true")
public class AuthController {
    // 登录接口等
}

额外:Shiro过滤器放行OPTIONS请求

因为浏览器在跨域复杂请求前会发OPTIONS预检请求,要确保Shiro不会拦截它:
在Shiro的配置类里,添加OPTIONS请求的放行规则:

@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    shiroFilterFactoryBean.setSecurityManager(securityManager);
    
    Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
    // 放行OPTIONS请求
    filterChainDefinitionMap.put("/api/**", "anon");
    // 其他规则...
    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
    
    return shiroFilterFactoryBean;
}

二、前端Angular配置请求携带凭证

接下来要让Angular的HttpClient在请求时带上Cookie,有两种方式:

方式1:单个请求设置withCredentials

在每次请求(比如登录、接口调用)时,添加withCredentials: true选项:

import { HttpClient } from '@angular/common/http';

// 登录请求示例
login(loginData: any) {
    return this.http.post('/api/login', loginData, {
        withCredentials: true // 关键:携带Cookie
    });
}

方式2:全局拦截器统一设置

如果不想每个请求都写一遍,可以创建一个HTTP拦截器,全局给所有请求添加withCredentials:

  1. 创建拦截器类:
import { Injectable } from '@angular/core';
import { HttpInterceptor, HttpRequest, HttpHandler, HttpEvent } from '@angular/common/http';
import { Observable } from 'rxjs';

@Injectable()
export class AuthInterceptor implements HttpInterceptor {
    intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
        // 克隆请求并添加withCredentials
        const modifiedRequest = request.clone({
            withCredentials: true
        });
        return next.handle(modifiedRequest);
    }
}
  1. 在AppModule里注册拦截器:
import { HTTP_INTERCEPTORS } from '@angular/common/http';
import { AuthInterceptor } from './auth.interceptor';

@NgModule({
    // ...其他配置
    providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: AuthInterceptor,
            multi: true
        }
    ]
})
export class AppModule { }

三、额外注意事项

  • 确保前端和后端的域名/端口是明确的跨域场景,比如后端localhost:8080,前端localhost:4200,如果是同域名同端口,不会有这个问题。
  • 测试时建议用浏览器无痕模式,避免旧的Cookie或缓存干扰。
  • 检查Shiro的会话配置,确保是默认的基于Cookie的会话管理(默认就是,除非你手动改了)。

按照上面的步骤配置后,Angular请求时就会自动携带JSESSIONID Cookie,后端就能正常保持会话了!

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 07:41:16