Springboot和vue前后端分離項目接入cas單點登錄,解決跨域


背景

這個問題也花了一兩天解決,寫到這里,記錄下來,同時也希望可以幫到別人,如有疑問或許改正的地方,還望不吝賜教!
項目背景是公司有多套后台管理系統,都是jsp或者thymeleaf前后端代碼在一起,接入的cas,實現一處登錄多處使用。

后業務發展,需要對其進行前后端分離,前端項目由vue完成,后台不同的管理模塊分別寫在不同的服務里。同時涉及到,新舊系統並存,jsp平台登錄后,前后端分離項目免登錄,同時解決跨域問題。

CSDN有幾遍介紹前后端分離接入cas的文章,都不盡完善,或者功能沒有完美實現。本文主要介紹了cas-server部署成功后,cas-client的接入,引用net.unicon.cas依賴,代碼侵入少,無需在filter上進行大量的自定義代碼。最后可以達到,用戶登錄了老的jsp項目后,在新的前后端分離項目中,可以成功請求后台接口,無需重新登錄或刷新。同時也可以實現,不同的cas-client之間共享session。

改造需要注意的點

  1. cookie的攜帶
  2. 不同服務之間cookie的共享
  3. clien-server授權后的頁面跳轉
  4. 跨域的配置

普通的cas接入

pom中引入依賴

<dependency>
  <groupId>net.unicon.cas</groupId>
  <artifactId>cas-client-autoconfig-support</artifactId>
  <version>2.3.0-GA</version>
</dependency>

配置cas-server地址,本地地址,validation-type(cas,cas3,sam的區別)

cas.server-url-prefix=https://****/cas
cas.server-login-url=https://****/cas/login
cas.client-host-url=http://****:8080
cas.validation-type=CAS

啟動配置注解

import net.unicon.cas.client.configuration.EnableCasClient;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
@EnableCasClient
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
}

如果要配置白名單,兩種方式

第一種

需要放行的url,可以繼承CasClientConfigurerAdapter類,重寫configureAuthenticationFilter

import net.unicon.cas.client.configuration.EnableCasClient;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Configuration;

import java.util.Map;


@Configuration
public class CasClientConfig extends CasClientConfigurerAdapter {
    @Override
    public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
        super.configureAuthenticationFilter(authenticationFilter);
        Map<String, String> initParameters = authenticationFilter.getInitParameters();
        // 配置地址,這里還可以配置很多,例如cas重定向策略等。
        initParameters.put("ignorePattern", "/ignoreUrl1/");
    }
}

同時啟動的SpringBootApplication 也要配置cookie可用

import net.unicon.cas.client.configuration.EnableCasClient;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;
import org.springframework.transaction.annotation.EnableTransactionManagement;


@SpringBootApplication
@EnableTransactionManagement
@EnableCasClient
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Bean
    public CookieSerializer httpSessionIdResolver() {
        DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer();
        cookieSerializer.setCookieName("JSESSIONID");
        cookieSerializer.setUseHttpOnlyCookie(false);
        cookieSerializer.setSameSite(null);
        return cookieSerializer;
    }
}

第二種方式

也可以配置需要攔截的url,不在配置內的就自動放行

cas.authentication-url-patterns=/need-filter-url/*,

前后端分離項目

接口接入cas-client,跨域問題及cookie攜帶需要配置

import net.unicon.cas.client.configuration.CasClientConfigurerAdapter;
import net.unicon.cas.client.configuration.EnableCasClient;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

import java.util.Map;


@Configuration
public class CasClientConfig extends CasClientConfigurerAdapter {
    @Override
    public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
        super.configureAuthenticationFilter(authenticationFilter);
        Map<String, String> initParameters = authenticationFilter.getInitParameters();
        initParameters.put("authenticationRedirectStrategyClass",
            "com.demo.filter.CustomAuthRedirectStrategy");
        // 配置地址,這里還可以配置很多,例如cas重定向策略等。
        initParameters.put("ignorePattern", "/ignoreUrl1/|/ignoreUrl2/|/ignoreUrl3/");
    }

    @Bean
    public FilterRegistrationBean corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
      	//前端頁面地址,可以配置多個
        config.addAllowedOrigin("http://****:8081");
        config.addAllowedOrigin("http://****:8081");
        config.addAllowedHeader("*");
        config.addAllowedMethod("*");
        source.registerCorsConfiguration("/**", config);
        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
        registrationBean.setFilter(new CorsFilter(source));
        //需要攔截的url
        registrationBean.addUrlPatterns("/url1/*");
      	registrationBean.addUrlPatterns("/url2/*");
      	registrationBean.addUrlPatterns("/url3/*");
        registrationBean.setOrder(-2147483648);
        return registrationBean;
    }
}

CustomAuthRedirectStrategy類

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;


public class CustomAuthRedirectStrategy implements AuthenticationRedirectStrategy {

    @Override
    public void redirect(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s) throws IOException {
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setContentType("application/json; charset=utf-8");
       	httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());

    }

}

前端代碼

http.js

import axios from 'axios'
import helper from './helper'
var qs = require('qs')
const ERR_CODE_LIST = { //常見錯誤碼列表
  [400]: "請求錯誤",
  [401]: "登錄失效或在其他地方已登錄",
  [403]: "拒絕訪問",
  [404]: "請求地址出錯",
  [408]: "請求超時",
  [500]: "服務器內部錯誤",
  [501]: "服務未實現",
  [502]: "網關錯誤",
  [503]: "服務不可用",
  [504]: "網關超時",
  [505]: "HTTP版本不受支持"
}
export function getErrMsg(error) {//通過error處理錯誤碼
  if(!error.response) {//無網絡時單獨處理
    return {errCode:null, errMsg:"網絡不可用,請刷新重試"}
  }
  const errCode = error.response.status //錯誤碼
  const errMsg = ERR_CODE_LIST[errCode] //錯誤消息

  return {errCode: errCode,errMsg: errMsg ? `${errMsg} [${errCode}]` : error.message}
}
// axios.defaults.withCredentials=true;//讓ajax攜帶cookie
// 引用axios,設置頭文件
function apiAxios(method,rootUrl, url, params) {
  return axios({
    method: method,
    url: url,
    data:qs.stringify(params),
    baseURL:rootUrl,
    timeout: 600000,
    dataType:"json",
    async: true,
    crossDomain: true,
    withCredentials:true
  }).catch(error => {
    const {errCode,errMsg} = getErrMsg(error);
    if(errCode == 401){
      //登錄失效 -> 跳轉登錄頁
      // http://****/cas/login 為cas-server的地址
			// http://******/front/redirect 為后台用於處理跳轉的地址
      let hurl = 'http://****:8080/front/redirect';
      window.location.href = 'http://****/cas/login?service=' + hurl;
    }else{
      showMsg(errMsg);
    }
    return Promise.reject(error)
})
}
export default {
  get: function (rootUrl,url, params) {
    return apiAxios('GET',rootUrl, url, params)
  },
  post: function (rootUrl,url, params) {
    return apiAxios('post',rootUrl, url, params)
  },
}

Api.js

import http from "./http";
let root = 'http://****:8080'
export default {
    // 用戶管理------------------
    getUserInfo(data) {
        return http.get( root, '/user/userInfo', data)
    },
}

user.vue

async getUserInfo() {
  let obj = {
    param1: value1
  };
  let userInfo = await this.$api.getUserInfo(obj);
  console.log(userInfo, '11');
},

跳轉處理地址

@RequestMapping(value = "redirect", method = RequestMethod.GET)
public void redirect(HttpServletRequest request, HttpServletResponse httpServletResponse)
  throws IOException {
  //重定向到前端頁面
  httpServletResponse.sendRedirect("http://****:8081/#/demo.html");
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM