Home >Web Front-end >JS Tutorial >How vue+springboot implements single sign-on cross-domain issues (detailed tutorial)

How vue+springboot implements single sign-on cross-domain issues (detailed tutorial)

亚连
亚连Original
2018-06-08 18:19:523309browse

This article mainly introduces the solution to the cross-domain problem of single sign-on by separating the front-end and back-end of vue springboot. Friends who need it can refer to it

I have been working on a back-end management system recently, and the front-end is very popular nowadays. vue.js, the background is based on springboot. Because the backend system does not have a login function, but the company requires unified login, the login authentication uses the authentication system of the .net project team. That means doing single sign-on. As for students who don’t know what single sign-on is, I suggest you go to the all-purpose Du Niang.

When I first received this requirement, I thought with disdain: Just logging in is not important. However, the development process slapped me hard (a hot slap). . . , so I must record this lesson carefully this time to avoid stepping into such pitfalls in the future.

The first problem I faced was cross-domain. The browser console directly reported CORS. With my many years of development experience, I decisively configured the cross-domain configuration in the background. 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 added 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<String, String> 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;
}

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 , you can jump directly to the single sign-on 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. After checking a lot of information, I found that I needed to add a configuration that allows authentication information to be added to the front end

axios.defaults.withCredentials=true;

The background also needs to make a corresponding configuration 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, re-execute the operation process and find that it works normally after logging in. Jump to the system and the page data is 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 confused. 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 directly and the next step can be performed. POST request.

The above is what I compiled for everyone. I hope it will be helpful to everyone in the future.

Related articles:

Solving the problem that webpack cannot access 127.0.0.1

##Using Async and Await function

Passing template to component in Angular

The above is the detailed content of How vue+springboot implements single sign-on cross-domain issues (detailed tutorial). For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn