Home  >  Article  >  Java  >  How to achieve single sign-on cross-domain by separating vue+springboot's front-end and back-end

How to achieve single sign-on cross-domain by separating vue+springboot's front-end and back-end

PHPz
PHPzforward
2023-05-11 23:13:051109browse

The code is as follows:

@Configuration
public class CorsConfiguration {
 @Bean
 public WebMvcConfigurer corsConfigurer() {
  return new WebMvcConfigurerAdapter() {
   @Override
   public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
      .allowedHeaders("*")
      .allowedMethods("*")
      .allowedOrigins("*");
   }
  };
 }
}

This configuration allows all mapping, all request headers, all request methods, and all sources. After changing the configuration, I decisively restarted the project to see the effect. I found that there was no way to redirect to the single sign-in page. Seeing that the browser error was caused by cross-domain, I first uploaded the code of my login interceptor

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
 //用户已经登录
 if (request.getSession().getAttribute("user") != null) {
  return true;
 }
 //从单点登录返回之后的状态,本系统还不处于登录状态
 //根据code值去获取access_token,然后再根据access_token去获取用户信息,并将用户信息存到session中
 String state = request.getParameter("state");
 String uri = getUri(request);
 if (isLoginFromSSO(state)) {
  String code = request.getParameter("code");
  Object cacheUrl = request.getSession().getAttribute(state);
  if (cacheUrl == null) {
   response.sendRedirect(uri);
   return false;
  }
  HttpUtil client = new HttpUtil();
  StringBuffer sb = new StringBuffer();
  sb.append("code=").append(code)
    .append("&grant_type=").append("authorization_code")
    .append("&client_id=").append(SSOAuth.ClientID)
    .append("&client_secret=").append(SSOAuth.ClientSecret)
    .append("&redirect_uri=").append(URLEncoder.encode((String) cacheUrl));
  String resp = client.post(SSOAuth.AccessTokenUrl, sb.toString());
  Map map = new Gson().fromJson(resp, Map.class);
  //根据access_token去获取用户信息
  String accessToken = map.get("access_token");
  HttpUtil http = new HttpUtil();
  http.addHeader("Authorization", "Bearer " + accessToken);
  String encrypt = http.get(SSOAuth.UserUrl);
  String userinfo = decryptUserInfo(encrypt);
  //封装成user对象
  User user = new Gson().fromJson(userinfo, User.class);
  request.getSession().setAttribute("user", user);
  return true;
 }
 //跳转到单点登录界面
 state = Const._SSO_LOGIN + Const.UNDERLINE + RandomUtil.getUUID();
 request.getSession().setAttribute(state, uri);
 String redirectUrl = buildAuthCodeUrl(uri, state);
 response.sendRedirect(redirectUrl);
 return false;
}

Later, the front-end vue requests the back-end login interface directly using

window.location.href=this.$api.config.baseUrl+"/system/user/login"

and then the front-end accesses the system and can jump directly to the single sign-in page. But when I entered my account and password and clicked to log in, I jumped back to the system and found that all request data interfaces could not be accessed normally. Debug found that all requests did not carry user information and were recognized by the interceptor as not logged in, so all requests could not pass. .

Why am I clearly logged in and the interceptor also sets user information to the session? Why are the cookies gone? I initiated a request again and found that the JsessionId of each request was different. I checked a lot of information and found that I needed to add a configuration that allows authentication information to be added to the front end.

axios.defaults.withCredentials=true;

A corresponding configuration also needs to be made in the backend allowCredentials(true );

@Bean
public WebMvcConfigurer corsConfigurer() {
 return new WebMvcConfigurerAdapter() {
  @Override
  public void addCorsMappings(CorsRegistry registry) {
   registry.addMapping("/**")
     .allowedHeaders("*")
     .allowedMethods("*")
     .allowedOrigins("*").allowCredentials(true);
  }
 };
}

After adding this configuration, I re-executed the operation process and found that after logging in, I can jump to the system normally and the page data is also displayed normally.

Just when I thought I was done, I suddenly clicked on a page and the data could not be displayed normally. I was so puzzled. I quickly F12 and found a request method I had never seen before, the OPTIONS request. It turns out that this request method is obviously POST, why did it become OPTIONS? So I ordered several other POST requests and found that they all turned into OPTIONS requests. I was confused and quickly checked the information of OPTIONS requests. The Internet said that OPTIONS requests are called "pre-check requests", which means that in your formal Before the request is executed, the browser will first initiate a pre-check request. Only after the pre-check request passes can the formal request be executed. After reading it, I suddenly realized that OPTIONS was intercepted, so I could no longer execute my POST request. Then I just let the pre-check request pass. Just add this judgment to the interceptor

//option预检查,直接通过请求
if ("OPTIONS".equals(request.getMethod())){
 return true;
}

In this way, if the interceptor finds that the request is a pre-check request, it will pass it directly, and the next POST request can be executed.

The above is the detailed content of How to achieve single sign-on cross-domain by separating vue+springboot's front-end and back-end. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete