相关文章推荐
温文尔雅的豆腐  ·  vue ...·  4 月前    · 
冷静的咖啡  ·  扩展器概述 - WPF .NET ...·  10 月前    · 
任性的滑板  ·  HttpRequestOptions.IDi ...·  10 月前    · 
微笑的伏特加  ·  provider:SQL Network ...·  1 年前    · 

参考资料一: 若依前后端分离版本集成CAS Server5.3

参考资料二: RuoYi-Vue前后端分离版集成cas

但是按照上述配置修改后会出现,一单点登录反复跳的情况, 经过排查发现是因为前端获取不到cookie, 所以导致前端被踢到了cas登录页

因为cas存在已通过的认证,所以又被带上ticket, 后台 CasAuthenticationSuccessHandler ,认证通过后重定向到了前台,因为是重定向所以出现了跨域的问题

所以80端口的虽然重定向设置了cookie但是还是获取不到 Admin-Token

ruoyi-ui\src\permission.js

import router from './router'
import store from './store'
import {Message} from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {getToken, setToken} from '@/utils/auth'
NProgress.configure({showSpinner: false})
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
const defaultSettings = require('@/settings.js')
router.beforeEach((to, from, next) => {
  NProgress.start()
    //这里获取不到token,也就是'Admin-Token'的cookie
  if (getToken()) {
    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
    /* has token*/
    if (to.path === '/login') {
      next({path: '/'})
      NProgress.done()
    } else {
        ......

解决办法:

  1. CasAuthenticationSuccessHandler在重定向是带上一个参数
  2. permission.js中增加一段逻辑,如果获取不到cookie,判断连接是不是指定的casUI,如果是则获取token,并手动set到cookie中
  3. ruoyi-admin\src\main\resources\application.yml 在这是前端登录地址的时候带上casUI,这样就可以了
package com.ruoyi.framework.security.handle;
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.framework.config.properties.CasProperties;
import com.ruoyi.framework.web.service.TokenService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
@Service
public class CasAuthenticationSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
	protected final Log logger = LogFactory.getLog(this.getClass());
	private RequestCache requestCache = new HttpSessionRequestCache();
	@Autowired
	private TokenService tokenService;
	@Autowired
	private CasProperties casProperties;
	 * 令牌有效期(默认30分钟)
	@Value("${token.expireTime}")
	private int expireTime;
	@Override
	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
										Authentication authentication) throws ServletException, IOException {
		String targetUrlParameter = getTargetUrlParameter();
		if (isAlwaysUseDefaultTargetUrl()
				|| (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
			requestCache.removeRequest(request, response);
			super.onAuthenticationSuccess(request, response, authentication);
			return;
		clearAuthenticationAttributes(request);
		LoginUser userDetails = (LoginUser) authentication.getPrincipal();
		String token = tokenService.createToken(userDetails);
		//往Cookie中设置token
		Cookie casCookie = new Cookie(Constants.WEB_TOKEN_KEY, token);
		casCookie.setMaxAge(expireTime * 60);
		response.addCookie(casCookie);
		//设置后端认证成功标识
		HttpSession httpSession = request.getSession();
		httpSession.setAttribute(Constants.CAS_TOKEN, token);
		//登录成功后跳转到前端登录页面,加了一个jwt参数
		getRedirectStrategy().sendRedirect(request, response, casProperties.getWebUrl()+"?jwt="+token);
import router from './router'
import store from './store'
import {Message} from 'element-ui'
import NProgress from 'nprogress'
import 'nprogress/nprogress.css'
import {getToken, setToken} from '@/utils/auth'
NProgress.configure({showSpinner: false})
const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
const defaultSettings = require('@/settings.js')
router.beforeEach((to, from, next) => {
  NProgress.start()
  if (getToken()) {
    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
    /* has token*/
    if (to.path === '/login') {
      next({path: '/'})
      NProgress.done()
    } else {
      if (store.getters.roles.length === 0) {
        // 判断当前用户是否已拉取完user_info信息
        store.dispatch('GetInfo').then(() => {
          store.dispatch('GenerateRoutes').then(accessRoutes => {
            // 根据roles权限生成可访问的路由表
            router.addRoutes(accessRoutes) // 动态添加可访问路由表
            next({...to, replace: true}) // hack方法 确保addRoutes已完成
        }).catch(err => {
          store.dispatch('LogOut').then(() => {
            Message.error(err)
            next({path: '/'})
      } else {
        next()
  } else {
    // 没有token
    if (whiteList.indexOf(to.path) !== -1) {
      // 在免登录白名单,直接进入
      next()
      //这里添加了指定的串casUI
    } else if (to.path === '/casUI') {
      let ticket = to.query.jwt
      setToken(ticket)
      //commit('SET_TOKEN', ticket)
      window.location.href = "/index"
      NProgress.done()
    } else {
      if (!defaultSettings.casEnable) {
        next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
      //开启cas
      if (defaultSettings.casEnable) {
        window.location.href = defaultSettings.casloginUrl // 否则全部重定向到登录页
      NProgress.done()
router.afterEach(() => {
  NProgress.done()
  server:
    host:
      #CAS服务地址
      url: http://localhost:8082/cas
      #CAS服务登录地址
      login_url: ${cas.server.host.url}/login
      #CAS服务登出地址
      logout_url: ${cas.server.host.url}/logout?service=${app.server.host.url}
# 应用访问地址
  #开启cas
  casEnable: true
  server:
    ip: localhost
    port: 80
    host:
      url: http://${app.server.ip}:${server.port}
  #应用登录地址
  login_url: /casLogin
  #应用登出地址
  logout_url: /casLogout
  #前端登录地址, 这里添加了指定的串casUI
  web_url: http://${app.server.ip}:${app.server.port}/casUI

唉, 就这破问题 搞了1天时间,希望可以帮助到别人,少走点弯路

附一张调用流程图, 也是我在排查问题时候梳理领悟所得,希望有用

基于SpringBoot + Vue前后端分离权限管理系统,可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。 技术栈:使用最流行的技术SpringBoot、Shiro、Thymeleaf、Vue、Bootstrap、MyBatis。
前后端分离的项目集成CAS 关于前后端分离的项目如何集成CAS,网上很少有资料博客,即便是有的也只是单纯的说下怎么做,并没有解释为什么,甚至大部分在前后端分离的项目中"成功"的集成cas的,也是懵懵懂懂. 本文从原理层面来进行一定的剖析,再来看如何解决. 采用环境:Tomcat 8.5,cas 3.4.1. 本文内容和Tomcat及cas版本关系不大. 主要涉及以下知识: cas认证原理,及客...
什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分.我们常见的实现框架有OAuth2和cas. 我下面的例子是基于其他博客的作者发给我的一个可运行示例进行一些说明, 实际上也就一个关键点, 一直困扰我们. cas服务5.2 springboot2.0.3 vue2.0 Tomcat8.5.39 这里需要注意, 我在内网运行cas服务端的时候,发现Tomcat8.0 什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分,如图(不标准,只是方便理解)。 一、CAS是什么? CAS 是 Yale 大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点 若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。 前端采用Vue、Element UI。 后端采用Spring Boot、Spring Security、Redis & Jwt。 权限认证使用Jwt,支持多终端认证系统。 支持加载动态权限菜单,多方式轻松权限控制。 高效率开发,使用代码生成器可以一键生成前后端代码。)
RuoYi是一个基于Spring Boot开发的前后端分离的快速开发平台,它的前端使用的是Vue.js框架,后端使用的是Spring Boot框架。在开发过程中,我们通常需要对接口文档进行管理和测试,这就需要使用Swagger进行接口文档的生成和测试。那么如何访问Swagger呢? 1. 在后端项目中添加Swagger依赖 在pom.xml中添加以下依赖: <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger2</artifactId> <version>2.9.2</version> </dependency> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-swagger-ui</artifactId> <version>2.9.2</version> </dependency> 2. 添加Swagger配置类 在后端项目中添加配置类SwaggerConfig,配置Swagger相关信息: @Configuration @EnableSwagger2 public class SwaggerConfig { @Bean public Docket createRestApi() { return new Docket(DocumentationType.SWAGGER_2) .apiInfo(apiInfo()) .select() .apis(RequestHandlerSelectors.basePackage("top.ruoyun.admin.system.controller")) .paths(PathSelectors.any()) .build(); private ApiInfo apiInfo() { return new ApiInfoBuilder() .title("RuoYi APIs") .description("Restful APIs document") .version("1.0") .build(); 3. 启动后端项目 启动后端项目,在浏览器中输入http://localhost:端口号/swagger-ui.html,即可进入Swagger页面。 4. 在前端项目中访问Swagger 在前端项目中添加axios依赖: npm install --save axios 在代码中使用axios进行接口访问: import axios from 'axios' //获取Swagger接口文档数据 export function getApiDocs() { return axios({ url: 'http://localhost:端口号/v2/api-docs', method: 'get' //获取Swagger接口文档URL export function getApiDocsUrl() { return axios({ url: 'http://localhost:端口号/swagger-ui.html', method: 'get' 在代码中调用getApiDocs()和getApiDocsUrl()函数,即可获取Swagger接口文档数据和URL。这样就可以在前端项目中访问Swagger,并进行接口文档的测试和管理了。 总的来说,在RuoYi前后端分离的开发过程中,访问Swagger的步骤比较简单,只需要在后端项目中添加Swagger依赖和配置类,然后在前端项目中使用axios进行接口访问即可。通过Swagger的使用,可以方便地管理和测试接口文档,提高开发效率和代码质量。