前后端分离,因跨域问题导致sessionId不一致,获取session为null的解决办法

本文记录了解决跨域请求下,Java中Session值在不同方法间无法共享的问题。通过调整CORSFilter代码,设置特定的允许跨域源,并在前端AJAX请求中加入withCredentials参数,成功实现了SessionID的一致性和Session值的正确获取。

     先来说说遇到的问题,在java中写了两个方法,暂且称之为A方法,B方法。 A方法中往session中存session.setAttribute("phoneMa",ma);在A方法中是可以取到phoneMa=session.getAttribute("phoneMa")的值,但是在B方法中获取phoneMa的值 phoneMa= session.getAttribute("phoneMa")一直为null。 百思不得解,然后查看两个方法中的sessionId=session.getId()是否一致,发现真的不一致。 这样,就找到了问题的所在。找资料发现:因为跨域问题SSIONID每次请求都会变化。而我的后台也设置了跨域请求

     我的跨域源码是:

public class CORSFilter implements Filter {

    public void init(FilterConfig filterConfig) throws ServletException {

    }

    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
       //*表示允许所有域名跨域
        httpResponse.addHeader("Access-Control-Allow-Origin", "*");
        //允许的请求头类型
        httpResponse.addHeader("Access-Control-Allow-Headers",
                "Origin, X-Requested-With, Content-Type, Accept");
        //允许跨域的Http方法
        httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
        filterChain.doFilter(servletRequest, servletResponse);
    }

    public void destroy() {

    }
}

     doFilter代码修改之后:

public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
    HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
    //*表示允许所有域名跨域
    httpResponse.addHeader("Access-Control-Allow-Origin", "http://127.0.0.1:8020");
    httpResponse.addHeader("Access-Control-Allow-Headers",
            "Origin, X-Requested-With, Content-Type, Accept");
    //允许跨域的Http方法
    httpResponse.addHeader("Access-Control-Allow-Methods", "GET,POST,PUT,DELETE");
    httpResponse.addHeader("Access-Control-Max-Age", "0");
    httpResponse.addHeader("Access-Control-Allow-Credentials","true");
    httpResponse.addHeader("XDomainRequestAllowed","1");
    filterChain.doFilter(servletRequest, servletResponse);
}

此时还不算完,需要在前端ajax请求上也要加入响应的代码。

xhrFields: {
     withCredentials: true
    },
crossDomain: true,

我的ajax请求是这样的:

				$.ajax({
						type: "post",						
						url: IP + "member/sendCode",
						//加上这句话
						xhrFields: {
           					withCredentials: true
       					},
       					crossDomain: true,
						data:{
							phone:inphone
						},
						success: function(data) {												
							console.log(JSON.stringify(data));	
							if(data.code == 200){
								
								
							}
						}
					});

这样再测试的时候,sessionId值是一样的,也能获取session的值了。
此文只作为笔记记录,可能会与其他大神写的内容雷同。 不喜勿喷!

### 前后端分离架构下的登录解决方案 在前后端分离的架构中,问题是常见的挑战之一。以下是针对登录问题的具体解决方案: #### 1. **理解机制** 同源策略是一种浏览器的安全措施,用于防止恶意网站通过脚本访问其他站点的数据。同源指的是协议、名和端口号都相同的情况[^2]。当客户端向同的源发起请求时,浏览器会自动触发预检请求(`OPTIONS`),以确认目标服务器是否允许此类操作。 #### 2. **CORS 配置** CORS 是一种标准化的资源共享方法,能够有效解决问题。可以通过以下几种方式进行配置: - **后端全局配置** 在 Spring Boot 中,可以创建一个配置类来处理请求。例如: ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许所有的路径 .allowedOrigins("*") // 允许所有来源 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 .allowCredentials(true); // 是否允许携带Cookie } } ``` 这种方式适用于开发阶段或简单的生产环境[^3]。 - **Nginx 反向代理** 使用 Nginx 来统一管理问题也是一种常见做法。可以在 `location` 模块中设置反向代理规则: ```nginx location /api/ { proxy_set_header Host $http_host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header REMOTE-HOST $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_pass http://backend_server_address/; } ``` 此外,在 Nginx 的配置文件中加入以下内容可进一步优化支持: ```nginx add_header Access-Control-Allow-Origin *; add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS'; add_header Access-Control-Allow-Headers 'Authorization, Content-Type'; ``` #### 3. **Token 认证与结合** 如果前端需要携带 Token 登录,则需要注意以下几点: - 浏览器会在首次发出 `OPTIONS` 请求时验证目标资源是否可用。因此,后端必须显式放行此请求[^1]。 - 确保后端接口返回正确的响应头,例如 `Access-Control-Allow-Credentials: true` 和 `Access-Control-Allow-Origin` 设置为具体的前端地址而非通配符 `*`。 #### 4. **代码示例** 下面展示了一个完整的登录流程实现: - **前端部分 (Vue.js)** 发起带 Token 的请求时,需确保设置了正确的 HTTP 头部信息: ```javascript axios.post('/api/login', { username: 'admin', password: 'password' }, { withCredentials: true, headers: { Authorization: localStorage.getItem('token') || '' } }).then(response => { console.log('Login successful:', response.data); }); ``` - **后端部分 (Spring Boot)** 创建一个过滤器来解析并校验 Token: ```java @Component public class JwtRequestFilter extends OncePerRequestFilter { private final MyUserDetailsService userDetailsService; public JwtRequestFilter(MyUserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { String authorizationHeader = request.getHeader("Authorization"); String token = null; String username = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { token = authorizationHeader.substring(7); try { username = jwtUtil.extractUsername(token); } catch (Exception e) { System.out.println("JWT Validation Error:" + e.getMessage()); } } if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) { UserDetails userDetails = this.userDetailsService.loadUserByUsername(username); if (jwtUtil.validateToken(token, userDetails)) { UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); SecurityContextHolder.getContext().setAuthentication(authenticationToken); } } chain.doFilter(request, response); } } ``` #### 5. **注意事项** - 若使用 Cookie 存储 Session ID 或 Token,则需要启用 `withCredentials=true` 并调整 CORS 配置中的 `allowedOrigins` 参数。 - 对于敏感数据传输,建议采用 HTTPS 协议加密通信通道。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值