单点登录CAS(一)搭建CAS - server服务器

CAS(一)搭建CAS - server服务器_Oumuv的博客-CSDN博客_cas server环境要求JDK 8+CAS 5.2tomcat 8+about CAScas document https://apereo.github.io/cas/5.2.x/index.htmlcas server 客户端模板下载 https://github.com/apereo/cas-overlay-template 步骤一、修改hosts文件,模拟跨域打开C:...https://blog.csdn.net/oumuv/article/details/83377945?spm=1001.2014.3001.5506CAS(四)基于Springboot搭建CAS-client,Springboot搭建CAS客户端

CAS(四)基于Springboot搭建CAS-client,Springboot搭建CAS客户端_Oumuv的博客-CSDN博客_cas springboot环境要求JDK 8+CAS 5.2tomcat 8+步骤一、搭建CAS服务器 -->CAS(一)搭建CAS - server服务器二、配置hosts,加入如下配置127.0.0.1 cas.server.com127.0.0.1 cas.client1.com三、搭建Springboot项目项目名为cas-clientB,项...简单总结:

1、pom依赖

<!-- 单点登录 -->
        <dependency>
			<groupId>org.jasig.cas.client</groupId>
			<artifactId>cas-client-core</artifactId>
			<version>3.2.1</version>
		</dependency>
		<dependency>
    		<groupId>net.unicon.cas</groupId>
    		<artifactId>cas-client-autoconfig-support</artifactId>
    		<version>2.3.0-GA</version>      
		</dependency>

2、application.properties配置

#单点登录前缀
cas.server-url-prefix=http://cas.server.com:8443/cas
#单点登录路径
cas.server-login-url=http://cas.server.com:8443/cas/login
cas.client-host-url=http://127.0.0.1:8088
cas.use-session=true
cas.validation-type=cas
server.port=8088
#自定义项目后台单点登录接口路径
client-host-url=http://127.0.0.1:8088/test/login/ssologin
#自定义项目前台单点登录接口路径-单点登录平台也是配置此路径
adminPath=http://127.0.0.1:9003/ssologin

3、CASAutoConfig配置类,配置需要匹配的url:

@Configuration
public class CASAutoConfig {
    @Value("${cas.server-url-prefix}")
    private String serverUrlPrefix;
    @Value("${cas.server-login-url}")
    private String serverLoginUrl;
    @Value("${cas.client-host-url}")
    private String clientHostUrl;
 
    /**
     * 授权过滤器
     * @return
     */
    @Bean
    public FilterRegistrationBean filterAuthenticationRegistration() {
        FilterRegistrationBean registration = new FilterRegistrationBean();
        registration.setFilter(new AuthenticationFilter());
        // 设定匹配的路径
        registration.addUrlPatterns("/login/ssologin");
        Map<String,String> initParameters = new HashMap<String, String>();
        initParameters.put("casServerLoginUrl",serverLoginUrl);
        initParameters.put("serverName", clientHostUrl);
        //忽略的url,"|"分隔多个url
        //initParameters.put("ignorePattern", "/logout/success|/index");
        registration.setInitParameters(initParameters);
        // 设定加载的顺序
        registration.setOrder(1);
        return registration;
    }
}

4、启动类加入开启cas client的注解

import net.unicon.cas.client.configuration.EnableCasClient;


@EnableCasClient//启用cas client

延用大神的图

springboot shardingsphere集成_nginx

 到这里非前后端分离的springboot+cas就搭建好了。

接下来解决前后端分离,跨域的问题

问题记录

在前后端分离情况下,AuthenticationFilter重定向问题,导致前端发生跨域

(1)描述
cas前后端不分离的情况下是能够直接跳转的,然而前后端分离后,前端ajax访问后端在经过AuthenticationFilter时,验证未登录会重定向到CAS登录,导致前端发生跨域问题

(2)解决思路
在AuthenticationFilter中不进行重定向,验证未登录就直接返回一个错误状态码;由前端获取到状态码后进行判断,再跳转到CAS登录地址

原先的 AuthenticationFilter

springboot shardingsphere集成_react_02

AuthenticationFilter 里的 doFilter方法

public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
        final HttpServletRequest request = (HttpServletRequest) servletRequest;
        final HttpServletResponse response = (HttpServletResponse) servletResponse;
        final HttpSession session = request.getSession(false);
        final Assertion assertion = session != null ? (Assertion) session.getAttribute(CONST_CAS_ASSERTION) : null;

        if (assertion != null) {
            filterChain.doFilter(request, response);
            return;
        }

        final String serviceUrl = constructServiceUrl(request, response);
        final String ticket = CommonUtils.safeGetParameter(request,getArtifactParameterName());
        final boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);

        if (CommonUtils.isNotBlank(ticket) || wasGatewayed) {
            filterChain.doFilter(request, response);
            return;
        }

        final String modifiedServiceUrl;

        log.debug("no ticket and no assertion found");
        if (this.gateway) {
            log.debug("setting gateway attribute in session");
            modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
        } else {
            modifiedServiceUrl = serviceUrl;
        }

        if (log.isDebugEnabled()) {
            log.debug("Constructed service url: " + modifiedServiceUrl);
        }

        final String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);

        if (log.isDebugEnabled()) {
            log.debug("redirecting to \"" + urlToRedirectTo + "\"");
        }

        response.sendRedirect(urlToRedirectTo);
    }

 在本地重写原先的 AuthenticationFilter,doFilter方法,对就是这么霸气。

public final void doFilter(final ServletRequest servletRequest, final ServletResponse servletResponse, final FilterChain filterChain) throws IOException, ServletException {
        filterChain.doFilter(servletRequest, servletResponse);      
    }

LoginController

@Value("${cas.server-login-url}")
    private String serverLoginUrl;
    @Value("${client-host-url}")
    private String clientHostUrl;
    @Value("${adminPath}")
    private String adminPath;

@RequestMapping(value = "/login/ssologin", method = RequestMethod.GET)
	public R ssoLogin(HttpSession session, HttpServletRequest request, HttpServletResponse response, Model model) {
		log.info("进入单点登录的方法 in sso method");
		// 如果是单点登录模式
			String ticket =request.getParameter("ticket");
			Assertion assertion = AssertionHolder.getAssertion();
			log.info("------------assertion:"+assertion);
			if(ticket==null)ticket=UUID.randomUUID().toString();
			if (assertion!=null) {
				Map<String, Object> map = new HashMap<>();
				String redirectUrl= request.getParameter("redirectUrl");
				log.debug("redirectUrl: " + redirectUrl);
	            try {
	            	if(redirectUrl != null){
                        // 单点登录成功后,重定向到前台url
	            		response.setHeader("Content-type", "text/html;charset=UTF-8");
		                response.sendRedirect(redirectUrl);
	            	} else {
	            		log.debug("Successfully authenticated user: " + assertion.getPrincipal().getName());
	    				String userid = assertion.getPrincipal().getName();
	    				SysUser user = getsysUser();//数据库查询用户
	    				if(ObjectUtils.isEmpty(user)) {
	    					throw new CEException("该账户不存在业务系统,请确认!");
	    				}
	    				map.put("result", user);
	            	}
	            } catch (IOException e) {
	                e.printStackTrace();
	            }
	            return R.ok().put("data", map);
			}
			// serverLoginUrl+"?service="+clientHostUrl+"?redirectUrl="+adminPath
		return R.ok("进行平台登录!").put("code", "401").put("serverLoginUrl", serverLoginUrl).put("service",clientHostUrl).put("redirectUrl",adminPath);
	}

react前端代码

// 单点登录用户未登录,打开认证中心登录地址并将前端地址作为参数传回,以便登录成功跳转到前端页面
if(res.code&&res.code=='401'){
    console.log('res.code', res.code);
    // serverLoginUrl+"?service="+clientHostUrl+"?redirectUrl="+adminPath
     let serverLoginUrl = res.serverLoginUrl;
     let service = res.service;
     let redirectUrl = res.redirectUrl;
    // 这里保存返回单点登录的地址
     localStorage.setItem("serverLoginUrl",serverLoginUrl);
     window.location.href = serverLoginUrl+"?service="+service+"?redirectUrl="+redirectUrl;
// window.location.href = 'http://cas.server.com:8443/cas/login?service=http://127.0.0.1:8088/test/login/ssologin?redirectUrl=http://127.0.0.1:9003/ssologin'
 }

简单复盘

1.第一次登录时,Assertion 为null,返回401code,并将各个URL返回。

2.前端将各个URL拼接,redirectUrl是登录成功后重定向的地址。

3.再次打开前台单点登录地址时,已登录成功,Assertion可以获取具体的用户。

4.根据用户到数据库查询权限角色,返回和登录一致的内容。