此时,假如是使用Oauth2协议,登录成功后,前端需要带着登录成功的信息(jwt),访问/Oauth2/1/authorize接口,此时该接口将会重定向回redirect_uri的地址,这个时候的重点在于如何访问/Oauth2/1/authorize接口。
我们列举一下几种请求方式:
根据以上方式做一个测试:
我们做一个302重定向的接口,重定向的路径是分别为http://localhost:3000/login和https://www.baidu.com,客户端的域名为localhost,情况如下图:

假如采用常用的Ajax,例如Axios或者Fetch,前端代码以及效果如下:



此时虽然不存在跨域问题了,但是重定向后的地址因为是使用XHR访问的,然而你客户端并没有开启Servlet等服务,故接口会返回404NotFound。















上述五种方式,Ajax和Fetch皆是异步请求,不能跟随浏览器302的操作,并且还获取不到接口返回的Location等信息,所以不采用。Form表单可以使用,功能也较为全面,但是实现方式较为复杂,且Form表单通常用于表单内容提交,与场景语义不符,故Pass**。Location.href的方式即以Get请求直接使用浏览器访问该接口,参数携带方便,也能跟随重定向操作,故采用。**
附上代码:
import serviceInstance from "../../services";
// const res = serviceInstance({
// url: "/redirectTo", //不用引入,直接在api后面接接口
// method: "get",
// data: {},
// });
// console.log(res);
function Home() {
const setRedirect = () => {
const res = serviceInstance({
url: "/redirectTo", //不用引入,直接在api后面接接口
method: "get",
data: {},
});
console.log(res);
};
const useFetchSetRedirect = () => {
const res = fetch("/redirectTo",{
method: "get",
redirect:'follow'
});
console.log(res);
};
const useLocationRedirect = () => {
window.location.href = "http://localhost:8080/redirectTo"
};
const useFormData = ()=>{
const form = document.createElement("form");
form.action = "http://localhost:8080/redirectTo";
document.getElementById("container").appendChild(form);
form.submit();
document.getElementById("container").removeChild(form);
}
const useSendBeacon = ()=>{
navigator.sendBeacon("http://localhost:8080/redirectToPost")
}
return (
);
}
export default Home;
package com.xuan.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
@RestController
public class TestController {
@GetMapping("/redirectTo")
void testRedirect(HttpServletResponse response) throws IOException {
String testUrl = "https://www.baidu.com";
// String testUrl2 = "http://localhost:3000/login";
response.sendRedirect(testUrl);
}
@PostMapping ("/redirectToPost")
void testRedirectPost(HttpServletResponse response) throws IOException {
String testUrl = "https://www.baidu.com";
// String testUrl2 = "http://localhost:3000/login";
response.sendRedirect(testUrl);
}
}
此时我们在重定向的过程中,需要传递信息给其他系统,仅有三种方式(据我所知):
浏览器地址栏携带
Cookie
Window.postMessage
子系统与认证中心同域
采用Cookie方式可以较为简单地实现单点登录,设置Cookie(access-token)到具体的域(Domain),通过Path去限制相应的系统,这样可以发挥认证中心实现单点登录的效果。但是浏览器必须把Cookie打开,以及应对Cookie具体设置对应的条件,以防其他系统通过CSRF等手段,获取到用户信息。
子系统与认证中心跨域
建议采用浏览器地址栏携传递信息,这个时候考虑到安全问题,不应该采用明文的形势将access-token放到地址栏,而是将重定向后携带的code通过地址栏传输回去子系统,然后子系统通过这个code调用接口获取access-token(采用空白页的方式)。
故排查原因,发现是因为重定向的接口的请求头中Host与后端设置的Domain不一致,Cookie被屏蔽掉了。报错如下图:

为此我做了个测试,模拟设置Cookie到百度的网站上:
首先设置Host文件(127.0.0.1 test.baidu.com),模拟百度的域名到本机ip;
然后在后端代码重定向到www.baidu.com,同时设置cookie到baidu.com这个域名上。
@GetMapping("/setCookieRedirect")
void testCookieRedirect(HttpServletResponse response) throws IOException {
String testUrl = "http://baidu.com";
Cookie cookie = new Cookie("testCookie","test");
cookie.setDomain("baidu.com");
cookie.setMaxAge(43200);
cookie.setSecure(false);
cookie.setHttpOnly(false);
response.addCookie(cookie);
response.sendRedirect(testUrl);
}
重点:前端调用该后端接口时,不可以用localhost调用,而是用test.baidu.com这个域名调用,如下:
const testThirdCookie = ()=>{
window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
}
最后成功设置Cookie到百度上,效果如下:

const testThirdCookie = ()=>{
window.location.href = "http://test.baidu.com:8080/setCookieRedirect"
}
最后成功设置Cookie到百度上,效果如下: