作者:后端小肥肠
🍇 我写过的文章中的相关代码放到了gitee,地址:xfc-fdw-cloud: 公共解决方案
🍊 有疑问可私信或评论区联系我。
🥑 创作不易未经允许严禁转载。
后端集成CAS单点登录:
【Spring Security系列】10分钟实现 SpringSecurity + CAS 完美单点登录方案_spring-security-cas-CSDN博客
目录
1. 前言
2. CAS单点登录流程梳理(全栈角度)
3. AI编程
3.1. AI编程前置工作
3.2. Cursor开发实战
4. 核心代码
4.1. 后端核心代码
4.2. 前端核心代码
5. 源码获取
6. 结语
当我在GitHub上看到那个刺眼的Issue——CAS前端集成谁来接?,突然意识到:在云原生和低代码的冲击下,单维度技术栈的生存空间正在急速收缩。作为Java程序员,我曾自豪于Spring生态的精通,却不得不在跨域请求和Cookie存储的迷雾中手足无措。
这种困境想必很多后端开发者都曾遇到:
但这也正是机遇所在:
🔑用AI工具突破技术边界,一个人就是一个全栈团队
🚀告别"我只会后端"的局限,拥抱全栈开发的未来
💡在技术转型的浪潮中抢占先机,提升个人竞争力
本文将展示如何用Cursor这把"技术杠杆":
话不多说,让我们开始这段打破技术边界的旅程...
CAS单点登录流程一共可以分为三大步骤:
1. 初始访问流程
当用户首次访问前端应用时(假设url为:http://localhost:8080/onemap),前端会自动发起一个API请求到后端服务。由于用户未登录,这个请求会被 Spring Security 的配置类(SecurityConfig)拦截。接着,认证入口点(AuthenticationEntryPointImpl)会返回401未授权状态码,并在响应头中携带CAS登录地址。前端的 axios 请求拦截器检测到401响应后,会自动将页面重定向到CAS统一认证登录页面,引导用户进行登录。
这就像是一个前台接待员(前端)帮访客(用户)问后台保安(后端)能否进入,保安发现访客没有通行证(未登录),就告诉前台让访客去登记处(CAS)办理通行证。
2. CAS登录认证流程
当用户在CAS统一认证系统中输入用户名和密码后,CAS服务器会对这些凭证进行验证。验证通过后,CAS服务器会生成一个一次性的服务票据(Service Ticket,简称ST)。然后,CAS服务器会将用户的浏览器重定向回我们的前端应用系统,同时在URL中附带上这个ST票据(例如:http://localhost:8080/onemap/#/login/cas?ticket=ST-xxx)。
这个过程就像是用户在统一认证中心获得了一张临时通行证,然后被引导回我们的系统入口。
3. Ticket验证流程
当CAS服务器将用户重定向回前端系统后,前端路由会将请求引导至专门处理CAS登录的组件(CasLogin)。该组件首先从URL中解析出CAS服务器颁发的票据(ticket)。然后,组件会调用后端的验证接口(/login/cas)并携带这个ticket。后端的CAS认证过滤器(CasAuthenticationFilter)会处理这个验证请求,验证ticket的有效性。如果验证通过,后端会创建会话并返回会话标识(JSESSIONID)给前端。最后,前端在确认登录成功后,会自动跳转到系统首页。
这个过程就像是用户拿着临时通行证(ticket)到前台(前端)登记,前台让保安(后端)验证通行证,验证通过后给用户发放正式通行证(JSESSIONID),然后引导用户进入大厅(首页)。
在使用AI进行编程之前,我们需要做好充分的准备工作。这个过程可以分为三个关键步骤:
1. 需求分析与技术储备
- 深入理解系统功能和业务流程
- 掌握相关技术栈的基础知识
- 明确项目的技术边界和实现目标
2. 前期流程梳理
- 详细梳理技术流程,以本文为例,需要在前期梳理CAS单点登录认证流程
- 设计数据流转和状态管理方案
3. 技术基础要求
虽然我们使用AI来协助开发,但仍需要了解相关基础知识(注意这里只是了解,不是让你花费几个月去拼命学),以本文为例,我们需要了解:
- 前端基础:HTML、CSS、JavaScript
- Vue.js基础概念:组件、生命周期、路由
- 开发环境:Node.js、NPM包管理
- 网络知识:HTTP协议、Cookie机制
需要强调的是,AI编程不是技术许愿池,而是一个强大的协作工具。它需要开发者具备足够的技术认知来进行需求分析、方案评估和问题排查。在本项目中,虽然我们使用AI实现了基于Vue2的CAS单点登录前端集成,但如果没有前端基础知识的支撑,在调试和问题排查阶段将会举步维艰。(只是我个人实践观点,你不要用网上那些非技术人员一天用Cursor开发了一个App还上线的例子来杠我,杠就是你对)
1. 说出你的需求,你想实现什么,让他给出方案(大概率是偏离的),比如我的需求就是基于后端已有代码,采用Vue2来进行CAS单点登录集成。
2. 把它给出的方案流程在你自己脑子里过一遍,不行的话需要修订:
AI会根据你提供的思路再给一版方案,我这里提示词没控制好,它直接开始写了,大家写的时候注意控制一下,方案没问题再开始写:
3. 验证AI写的代码,进入前端目录(AI生成代码的目录),运行npm install安装依赖,之后运行npm run serve,先把代码跑起来看看:
我们再把后台启动一下,访问前端url的时候直接跳转到了CAS登录界面:
输入用户名和密码后,跳转到了首页,接口数据拿到了:
到此,单点登录集成完成了。(其实很多调试步骤没有被列出来,流程梳理也很费时间,这里大家自己实践就知道了)
虽然之前的文章(【Spring Security系列】10分钟实现 SpringSecurity + CAS 完美单点登录方案_spring-security-cas-CSDN博客)已经包含详尽的后端代码,但对接到前端还需要改一下,具体修改如下:
1. 后端认证入口点(这里需要改一下,之前是直接重定向到CAS认证界面了,现在要返回401,由前端来跳转到CAS认证界面)
@Componentpublic class AuthenticationEntryPointImpl implements AuthenticationEntryPoint { @Value("${ cas.server}") private String casServerUrl; @Value("${ cas.client}") private String casClientUrl; @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException { // 构建CAS登录URL,带上service参数 String serviceUrl = casClientUrl + "/#/login/cas"; String casLoginUrl = casServerUrl + "/login?service=" + URLEncoder.encode(serviceUrl, "UTF-8"); response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setHeader("Location", casLoginUrl); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{ \"message\":\"未登录或登录已过期\"}"); }}
2. 修改SecurityConfig配置
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception { http .httpBasic().disable() .csrf().disable() .formLogin().disable() .logout().disable() .authorizeHttpRequests(authorizeHttpRequests -> authorizeHttpRequests .antMatchers("/login/cas", "/logout/cas").permitAll() .antMatchers("/error").permitAll() .antMatchers("/swagger-ui.html").permitAll() .antMatchers("/swagger-resources/**").permitAll() .antMatchers("/v2/api-docs").permitAll() .antMatchers("/webjars/**").permitAll() .antMatchers("/doc.html").permitAll() .anyRequest().authenticated()) .exceptionHandling() .authenticationEntryPoint(authenticationEntryPoint) .and() .addFilter(casAuthenticationFilter()) .addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class) .addFilterBefore(casLogoutFilter(), LogoutFilter.class); return http.build();}
@Bean public ServiceProperties serviceProperties() { ServiceProperties serviceProperties = new ServiceProperties(); serviceProperties.setService("http://localhost:8080/onemap/#/login/cas"); serviceProperties.setAuthenticateAllArtifacts(true); return serviceProperties; }
setService()设置的URL就是CAS服务器回调的地址,会带上ticket参数,我们需要将其改为前端地址(我的前端地址为http://localhost:8080/onemap)。
@Beanpublic CasAuthenticationFilter casAuthenticationFilter() throws Exception { CasAuthenticationFilter filter = new CasAuthenticationFilter(); // 1. 设置认证管理器 filter.setAuthenticationManager(authenticationManager()); // 2. 设置处理ticket验证的URL路径 filter.setFilterProcessesUrl("/login/cas"); // 3. 设置service配置 filter.setServiceProperties(serviceProperties()); // 4. 认证成功处理器 filter.setAuthenticationSuccessHandler((request, response, authentication) -> { response.setContentType("application/json;charset=UTF-8"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().write("{ \"status\":\"200\",\"message\":\"登录成功\"}"); }); // 5. 认证失败处理器 filter.setAuthenticationFailureHandler((request, response, exception) -> { response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); response.setHeader("Location", casServerUrl + "/login"); response.setContentType("application/json;charset=UTF-8"); response.getWriter().write("{ \"message\":\"认证失败\"}"); }); return filter;}
CAS认证过滤器(CasAuthenticationFilter),用于处理CAS服务器回调时的ticket验证。它设置了认证管理器来处理认证逻辑,指定/login/cas作为处理ticket验证的URL路径,并注入service配置来指定CAS回调地址。同时配置了两个关键的处理器:认证成功时返回200状态码和成功消息,并自动设置JSESSIONID;认证失败时返回401状态码,并在响应头中设置CAS登录地址以便前端重新发起登录。
1. 前端拦截请求器
// utils/request.jsservice.interceptors.response.use( response => response, error => { if (error.response?.status === 401) { window.location.href = error.response.headers.location; return; } Message.error(error.message); return Promise.reject(error); })
这段代码是前端的axios响应拦截器配置,主要用于统一处理后端接口响应。当接口请求成功时直接返回响应数据;当请求失败时,会检查是否是401未授权错误(表示用户未登录),如果是401则从响应头中获取CAS登录地址并进行页面跳转,否则显示错误消息并将Promise设为rejected状态。
2. 前端CAS回调处理
// views/login/CasLogin.vueexport default { methods: { getTicketFromUrl() { const url = window.location.href; const hashIndex = url.indexOf('#'); const queryString = hashIndex > -1 ? url.substring(0, hashIndex) : url; const urlParams = new URLSearchParams(queryString.split('?')[1]); return urlParams.get('ticket'); }, async handleLogin() { try { const ticket = this.getTicketFromUrl(); const response = await validateTicket(ticket); if (response.status === 200) { this.$router.push('/'); } } catch (error) { this.error = error.message; } } }}
这段代码是CAS登录回调处理组件的核心方法,主要完成两个任务:getTicketFromUrl方法负责从URL中解析CAS服务器回调时携带的ticket参数(处理类似http://localhost:8080/onemap/#/login/cas?ticket=ST-xxx这样的URL);handleLogin方法则负责调用后端接口验证这个ticket的有效性,如果验证成功(返回200状态码)就跳转到系统首页,验证失败则显示错误信息。
关注gzh后端小肥肠,点击底部【资源】菜单就能获取前端源码,后端源码已经很详尽,不再提供。
这次CAS集成的实战,远不止实现一个功能这么简单。它证明了:在AI工具的加持下,后端程序员完全能驾驭前端关键模块。
🎯 技术成长启示
1️⃣ AI不是万能的,但懂AI的程序员是万能的
2️⃣ 技术边界正在消失,全栈思维是必备技能
3️⃣学会用AI工具,让你的能力突破天际
📚你的下一步行动:
1️⃣ 立即下载源码
2️⃣ 参考往期《【Spring Security系列】10分钟实现 SpringSecurity + CAS 完美单点登录方案》,构建高可用认证体系
3️⃣ 安装Cursor,用我的方法尝试一下AI编程(你会回来谢我)
如果本文对你有帮助,请动动你发财的小手点点关注,小肥肠将持续分享更多AI干货文章~