SpringBoot前后端分离整合cas(客户端)

SpringBoot前后端分离整合cas(客户端)

cas认证详细流程:
在这里插入图片描述
前后端分离:项目前端使用nginx启动,后端是springBoot服务;
nginx可以统一管理Cookie,避免出现跨域问题。

添加依赖

  <dependency>
            <groupId>org.jasig.cas.client</groupId>
            <artifactId>cas-client-support-springboot</artifactId>
            <version>3.6.2</version>
  </dependency>

配置文件添加

cas:
  # cas服务端地址,nginx代理
  server-url-prefix: http://127.0.0.1:9010/cas
  # cas服务端登录地址,nginx代理
  server-login-url: http://127.0.0.1:9010/cas/login
  # 当前服务程序地址,nginx代理
  client-host-url: http://127.0.0.1:9010
  validation-type: cas3
  
# 不校验权限路径(正则表达式)
ignorePattern: ".*\\/api\\/rest\\/test\\/.*|.*\\/test\\/hello"

启动类添加注解@EnableCasClient

@EnableCasClient
@SpringBootApplication
public class TestApplication extends SpringBootServletInitializer {

    public static void main(String[] args) {
        SpringApplication.run(TobApplication.class, args);
    }
    
    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application.sources(TobApplication.class);
    }
}

重写cas客户端配置

@Configuration
public class SmsCasClientConfigurer implements CasClientConfigurer {
    @Value("${host-url}")
    private String serverName;
    @Value("${ignorePattern}")
    private String ignorePattern;
    @Value("${cas.server-login-url}")
    private String serverLoginUrl;
    @Value("${casLogin-url}")
    private String casLoginUrl;

    @Override
    public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
        Map initParameters = authenticationFilter.getInitParameters();
        // 设置不校验权限路径  
        initParameters.put("ignorePattern", ignorePattern);  
    } 
}

默认Get接口

@RestController
@RequestMapping("/api/common")
public class CommonController {
    @GetMapping("/getUserName")
    public String getUserName(HttpServletRequest request) {
        if(request.getUserPrincipal()!=null){
        	return request.getUserPrincipal().getName();
        }else{
			return "";
		}
    }

前端添加拦截

我的前端使用的vue,若不是可以参考文章底部博客。

前端登陆之后cas服务端会默认添加"TGC"的cookie到浏览器,然后会跳转到前端页面,前端首次去访问后端程序时需要验证票据,所以默认第一个请求接口尽量是get请求,若是post可能会被cas重定向成get。下面的2,3步你也可以不做,直接在路由守卫permission.js中直接调用接口,根据自己的实际情况使用此博客即可。

1,get请求接口src\api\commonAPI.js

import { httpServer } from 'axios'

export function getUserNameAPI (data) {
  return httpServer.get(`api/common/getUserName`);
}

2,设置缓存src\store\modules\user.js

import { getUserNameAPI } from "@/api/commonAPI.js";

const state = {
  username: ""
}

/*从session获取username,vue页面中可调用:如下示例
...
{{getUserName}}
...
computed: {
    ...mapGetters(["getUserName"]),
}
...
*/
const getters = {
  getUserName: state => {
    var name;
    if (sessionStorage.getItem('username')) {
      name= sessionStorage.getItem('username');
    } else {
      name= state.username;
    }
    return name;
  }
}

const mutations = {
  ["SET_USER_NAME"](state, data) {
    state.username = data === null ? "" : data;
    sessionStorage.setItem('username',data)
  }
}

//调用接口并添加username到session中
const actions = {
  getUserName({commit}) {
    return new Promise(resolve => {
      getUserNameAPI().then(res => {
        commit("SET_USER_NAME", res);
        resolve()
      });
    })
  }
}

export default {
  state,
  getters,
  mutations,
  actions
};

3,添加user.js到src\store\index.js

import Vue from "vue";
import Vuex from "vuex";
import createPersistedState from "vuex-persistedstate";
import user from "./modules/user";

Vue.use(Vuex);

export default new Vuex.Store({
  modules: {
    user
  },
  plugins: [createPersistedState({ storage: window.sessionStorage })]
});

4,修改路由守卫src\permission.js

//路由拦截
import  {Spin} from "view-design";
import "view-design/dist/styles/iview.css";
import router from "./router";
import store from "./store";
import Cookies from "js-cookie";

Spin.show({
  render: (h) => {
    return h('div', [
      h('div', '登录中...')
    ])
  }
})

router.beforeEach((to, from, next) => {
  //走cas校验
  if(true){
    let CUR_URL = window.location.href;
    //判断是否存在TGC的Cookies,不存在则跳转到cas登录页面登录,登陆成功之后cas服务端会添加TGC的Cookies到浏览器中
    let CASTGC_COOKIE = Cookies.get("TGC")?true:false;
    if (CASTGC_COOKIE) {
      // 登录
      if (CUR_URL.indexOf("?ticket") > -1) {
        window.location.href = CUR_URL.split("?ticket")[0];
      }
      Promise.all([store.dispatch('getUserName')]).then(opts => {
        Spin.hide();
        next();
      })
    } else {
      window.location.href = `http://127.0.0.1:9010/cas/login?service=${window.location}`;
    }
  } else {
    //不走cas校验
    Promise.all([store.dispatch('getUserName')]).then(opts => {
      Spin.hide();
      next();
    })
  }
});

nginx代理

worker_processes  1;
events {
    worker_connections  1024;
}
http {
	include /etc/nginx/mime.types;
    default_type application/octet-stream;
    		
    sendfile on;
    keepalive_timeout 65;
    
	server {
        	listen       9010;
        	server_name  127.0.0.1;
        	
        	#nginx代理前端
			location / {
            	autoindex on;
            	add_header Access-Control-Allow-Origin *;
            	add_header Access-Control-Allow-Methods 'GET, POST, OPTIONS';
            	# 静态资源位置
            	alias /usr/share/nginx/html;
            	index  index.html;
            	try_files $uri $uri/ /index.html last;
        	}
			
			#我的后端服务,my_server为我的服务前缀
			location ^~  /my_server/ {
            	proxy_pass http://127.0.0.1:8091/my_server/;
            	add_header Access-Control-Allow-Origin *;
            	proxy_cookie_path /my_server/ /;  #解决nginx转发丢失cookie的问题

            	# 支持 OPTIONS 请求,并设置预检请求结果的缓存时间
            	if ($request_method = 'OPTIONS') {
                	add_header 'Access-Control-Max-Age' 1728000;
                	add_header 'Content-Type' 'text/plain charset=UTF-8';
                	add_header 'Content-Length' 0;
                	return 204;
            	}
         	}

			#cas服务端
			location ^~  /cas/ {
            	proxy_pass http://127.0.0.1:8092/cas/;
            	add_header Access-Control-Allow-Origin *;
            	proxy_cookie_path /cas/ /;  #解决nginx转发丢失cookie的问题

            	# 支持 OPTIONS 请求,并设置预检请求结果的缓存时间
            	if ($request_method = 'OPTIONS') {
                	add_header 'Access-Control-Max-Age' 1728000;
                	add_header 'Content-Type' 'text/plain charset=UTF-8';
                	add_header 'Content-Length' 0;
                	return 204;
            	}
         	}
     }
}

参考博客:
https://blog.youkuaiyun.com/weixin_41358538/article/details/130880319

Spring Boot前后端分离架构下集成CAS实现单点登录(SSO),需要结合前端和后端的协作来完成身份验证流程。以下是关键步骤和技术要点: ### 3.1 配置依赖项 首先,在`pom.xml`中添加必要的CAS客户端依赖,以支持与CAS服务器的交互[^2]: ```xml <dependency> <groupId>org.jasig.cas.client</groupId> <artifactId>cas-client-core</artifactId> <version>3.6.2</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> ``` 这些依赖提供了对CAS协议的支持以及Spring Security的安全框架整合能力。 ### 3.2 配置CAS属性 在`application.yml`或`application.properties`中配置CAS服务器的URL、服务URL等信息: ```yaml cas: server: url: https://your-cas-server.com/cas service: url: http://localhost:8080 ``` 这些配置将用于构建认证请求和服务回调地址。 ### 3.3 创建CAS配置类 创建一个Spring Configuration类,用于注册CAS相关的过滤器和监听器。该类通常包括以下组件: - `AuthenticationFilter`:负责处理用户登录请求并重定向到CAS服务器。 - `SingleSignOutHttpSessionListener`:用于监听会话结束事件,实现单点登出功能。 - `CasAuthenticationEntryPoint`:定义未认证用户的访问入口点。 示例代码如下: ```java @Configuration public class CasConfig { @Value("${cas.server.url}") private String casServerUrl; @Value("${cas.service.url}") private String serviceUrl; @Bean public FilterRegistrationBean<AuthenticationFilter> casAuthenticationFilter() { FilterRegistrationBean<AuthenticationFilter> registration = new FilterRegistrationBean<>(); registration.setFilter(new AuthenticationFilter()); registration.addInitParameter("casServerLoginUrl", casServerUrl + "/login"); registration.addInitParameter("serverName", serviceUrl); registration.addUrlPatterns("/*"); return registration; } @Bean public ServletListenerRegistrationBean<SingleSignOutHttpSessionListener> casSingleSignOutListener() { return new ServletListenerRegistrationBean<>(new SingleSignOutHttpSessionListener()); } @Bean public CasAuthenticationEntryPoint casAuthenticationEntryPoint() { CasAuthenticationEntryPoint entryPoint = new CasAuthenticationEntryPoint(); entryPoint.setLoginUrl(casServerUrl + "/login"); entryPoint.setServiceProperties(serviceProperties()); return entryPoint; } @Bean public ServiceProperties serviceProperties() { ServiceProperties properties = new ServiceProperties(); properties.setService(serviceUrl + "/login/cas"); properties.setSendRenew(false); return properties; } } ``` 此配置类通过`@Bean`注解声明了多个Spring Bean,并设置了相应的初始化参数,确保系统能够正确地与CAS服务器进行通信。 ### 3.4 安全配置 为了保护应用程序资源并启用CAS认证机制,还需要配置Spring Security。创建一个继承自`WebSecurityConfigurerAdapter`的配置类,并覆盖默认的安全策略: ```java @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CasAuthenticationEntryPoint casAuthenticationEntryPoint; @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/public/**").permitAll() .anyRequest().authenticated() .and() .exceptionHandling() .authenticationEntryPoint(casAuthenticationEntryPoint) .and() .addFilterBefore(new CasAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class); } } ``` 在这个安全配置中,所有未授权的请求都将被引导至CAS认证页面。此外,还启用了`CasAuthenticationFilter`来拦截请求并验证用户身份。 ### 3.5 处理跨域问题 由于前后端分离项目通常运行在不同的域名或端口上,因此必须处理CORS(跨源资源共享)问题。可以通过添加全局CORS配置来解决这一问题: ```java @Configuration public class CorsConfig implements WebMvcConfigurer { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins("*") .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") .allowedHeaders("*") .exposedHeaders("X-CAS-ProxyReceptorUrl", "X-CAS-ServiceTicket"); } } ``` 这段代码允许来自任何来源的请求,并暴露特定的HTTP头,以便前端可以获取CAS票据等信息。 ### 3.6 前端集成 前端部分需要根据CAS协议发起认证请求,并处理返回的结果。通常情况下,前端可以通过重定向方式跳转到CAS服务器的登录页面,或者使用AJAX请求获取临时票据。一旦获得有效的TGT(Ticket Granting Ticket),就可以将其存储在本地存储或Cookie中,并在后续请求中携带该票据进行身份验证。 对于Vue.js项目,可以在路由守卫中判断是否已经登录,如果没有则跳转到CAS登录页面: ```javascript router.beforeEach((to, from, next) => { if (!store.getters.isLoggedIn && to.path !== '/login') { window.location.href = 'https://your-cas-server.com/cas/login?service=' + encodeURIComponent('http://localhost:8080/api/login'); } else { next(); } }); ``` 以上是关于如何在Spring Boot前后端分离架构下集成CAS实现单点登录的基本流程和关键技术点。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值