#单点登录解决方案CAS
##一、单点登录
单点登录SSO,实现跨域登录。当用户第一次访问系统的时候,会被引导进入认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份校验,如果通过校验,应该返回给用户一个认证的凭据service tikiet;在用户访问其他业务或者说下次访问的时候,客户端就会带上当前的凭据,服务端通过当前cookie中所携带的service tikiet进行验证,判断该用户是否登录。
###1.1 同域下的单点登录
首先从传统的登录验证方式来看:
如上图所示,我们在浏览器(Browser)中访问一个应用,这个应用需要登录,我们填写完用户名和密码后,完成登录认证。这时,我们在这个用户的session中标记登录状态为yes(已登录),同时在浏览器(Browser)中写入Cookie,这个Cookie是这个用户的唯一标识。下次我们再访问这个应用的时候,请求中会带上这个Cookie,服务端会根据这个Cookie找到对应的session,通过session来判断这个用户是否登录。如果不做特殊配置,这个Cookie的名字叫做jsessionid,值在服务端(server)是唯一的。
同域下的单点登录主要针对同级域名下的所有系统,例如www.sso.a.com ,www.app1.a.com,www.app2.a.com。在同域下实现单点登录:首先要考虑seesion的存储,其次是seesion的共享问题;
第一步,将sso存储的cookie域设置为顶级域,如何设置呢?
如果想所有a.com名下的二级域名都可以使用该Cookie,需要设置Cookie的domain参数
Cookie cookie = new Cookie(); // 新建Cookie
cookie.setDomain(".a.com"); // 设置域名
这样app1和app2就能够使用顶级域的cookie信息,但是seesion是存在于不同应用下,是不能够共享的。
###1.2 跨域单点登录
跨域下的单点登录是指,在不同URL地址,两者属于不用的服务器。不同域之间Cookie是不共享的,,就无法通过cookie的来实现登录验证。
下面通过对CAS官网的时序图解析进一步完成对跨域cas的认识和理解:
时序图流程解析:
1、user通过浏览器发出get请求,请求app服务,但是此时用在没有登录。
2、跳转到CAS server,即SSO登录系统,以后图中的CAS Server我们统一叫做SSO系统。 SSO系统也没有登录,弹出用户登录页。
3、用户在登录页填写用户名、密码,SSO系统进行认证后,将登录状态写入SSO的session,浏览器(Browser)中写入SSO域下的Cookie。
4、SSO系统登录完成后会生成一个ST(Service Ticket),然后跳转到app系统,同时将ST作为参数传递给app系统。
5、app系统拿到ST后,从后台向SSO发送请求,验证ST是否有效。
6、验证通过后,app系统将登录状态写入session并设置app域下的Cookie。
至此,跨域单点登录就完成了。以后我们再访问app系统时,app就是登录的。接下来,我们再看看访问app2系统时的流程。
- 用户访问app2系统,app2系统没有登录,跳转到SSO。
- 由于SSO已经登录了,不需要重新登录认证。
- SSO生成ST,浏览器跳转到app2系统,并将ST作为参数传递给app2。
- app2拿到ST,后台访问SSO,验证ST是否有效。
- 验证成功后,app2将登录状态写入session,并在app2域下写入Cookie
##二、CAS
###1、客户端开发
####1.1.原生方式
通过web.xml方式进行配置
1.jar包依赖
<dependencies>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.3.3</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
2.web.xml 配置文件解析
<!-- ===================单点登录 ============================-->
<!--=用于单点登出,该过滤器用于实现单点登出功能,可选择配置-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!– 该过滤器用于实现单点登出功能,可选配置–>
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!–该过滤器负责用户的认证工作,必须配置–>
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>http://localhost:8080/cas/login</param-value>
<!–cas的服务端ip–>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:9001</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!–该过滤器负责对ticket的校验工作,必须配置–>
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>http://localhost:8080/cas/</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:9001</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!–该过滤器负责实现httpServletRequst请求的包裹,例如开发者需要通过httpServletRequst的getRemoteUser()方法获取登录的用户名–>
<filter>
<filter-name>CAS httpServletRequst Wrapper Filter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS httpServletRequst Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>-->
//当通过浏览器访问该地址的所有资源时,进行登录验证,进入>http://localhost:8080/cas,完成登录之后,可正常访问所有当前项目下的资源。
####1.2 spring Sercurity整合cas
配置文件: web.xml spring-sercurity.xml cas.properties
1. jar包依赖
<packaging>war</packaging>
<properties>
<spring.version>5.0.5.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-cas</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.3.3</version>
<exclusions>
<exclusion>
<groupId>org.slf4j</groupId>
<artifactId>log4j-over-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<configuration>
<!-- 指定端口 -->
<port>9003</port>
<!-- 请求路径 -->
<path>/</path>
</configuration>
</plugin>
</plugins>
</build>
2. web.xml—配置Sercurity过滤器
<!--spring Security整合-->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
3. spring-sercurity.xml ---- 配置spring-sercurity和cas
<!-- entry-point-ref 入口点引用 -->
<http use-expressions="false" entry-point-ref="casProcessingFilterEntryPoint">
<intercept-url pattern="/login/*.do" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
<intercept-url pattern="/**" access="ROLE_USER"/>
<csrf disabled="true"/>
<!-- custom-filter为过滤器, position 表示将过滤器放在指定的位置上,before表示放在指定位置之前 ,after表示放在指定的位置之后 -->
<custom-filter ref="casAuthenticationFilter" position="CAS_FILTER" />
<custom-filter ref="requestSingleLogoutFilter" before="LOGOUT_FILTER"/>
<custom-filter ref="singleLogoutFilter" before="CAS_FILTER"/>
</http>
<!-- CAS入口点 开始 -->
<beans:bean id="casProcessingFilterEntryPoint" class="org.springframework.security.cas.web.CasAuthenticationEntryPoint">
<!-- 单点登录服务器登录URL -->
<beans:property name="loginUrl" value="${cas_url}/login"/>
<beans:property name="serviceProperties" ref="serviceProperties"/>
</beans:bean>
<beans:bean id="serviceProperties" class="org.springframework.security.cas.ServiceProperties">
<!--service 配置自身工程的根地址+/login/cas -->
<beans:property name="service" value="${service_url}/login/cas"/>
</beans:bean>
<!-- CAS入口点 结束 -->
<!-- 认证过滤器 开始 -->
<beans:bean id="casAuthenticationFilter" class="org.springframework.security.cas.web.CasAuthenticationFilter">
<beans:property name="authenticationManager" ref="authenticationManager"/>
</beans:bean>
<!-- 认证管理器 -->
<authentication-manager alias="authenticationManager">
<authentication-provider ref="casAuthenticationProvider">
</authentication-provider>
</authentication-manager>
<!-- 认证提供者 -->
<beans:bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
<beans:property name="authenticationUserDetailsService">
<beans:bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
<beans:constructor-arg ref="userDetailsService" />
</beans:bean>
</beans:property>
<beans:property name="serviceProperties" ref="serviceProperties"/>
<!-- ticketValidator 为票据验证器 -->
<beans:property name="ticketValidator">
<beans:bean class="org.jasig.cas.client.validation.Cas20ServiceTicketValidator">
<beans:constructor-arg index="0" value="${cas_url}"/>
</beans:bean>
</beans:property>
<beans:property name="key" value="an_id_for_this_auth_provider_only"/>
</beans:bean>
<!-- 认证类 -->
<beans:bean id="userDetailsService" class="com.qingcheng.service.UserDetailServiceImpl"/>
<!-- 认证过滤器 结束 -->
<!-- 单点登出 开始 -->
<beans:bean id="singleLogoutFilter" class="org.jasig.cas.client.session.SingleSignOutFilter"/>
<beans:bean id="requestSingleLogoutFilter" class="org.springframework.security.web.authentication.logout.LogoutFilter">
<beans:constructor-arg value="${cas_url}/logout?service=${service_url}"/>
<beans:constructor-arg>
<beans:bean class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler"/>
</beans:constructor-arg>
<beans:property name="filterProcessesUrl" value="/logout/cas"/>
</beans:bean>
<!-- 单点登出 结束 -->
详细解析:
- use-expressions="false"是否开启spel表达式,springEl表达式。
- entry-point-ref=“casProcessingFilterEntryPoint” 切入点设置,如果需要加载第三方接口,在使用了第三方认证接口之后,需要在后面进行改接口的bean配置。
- custom-filter ref=“casAuthenticationFilter” position=“CAS_FILTER” cas认证过滤器,CAS_FILTER是spring-security原有的过利器,通过potion属性指定位置,替换原有的过滤器。
- custom-filter ref=“requestSingleLogoutFilter” before=“LOGOUT_FILTER” 请求单点退出过滤器。before,在XX之前,在LOGOUT_FILTER过滤器之前加上请求单点退出过滤器。
- singleLogoutFilter 单点退出过滤器。
- CAS入口点:
- loginUrl 配置cas的入口地址,也叫作CAS server用户凭证地址。
- serviceProperties 配置web服务器地址(项目地址),通过该值在CAS serve上生成service ticket。
- casAuthenticationFilter 指定认证提供者 ——> authenticationManager 指定认证管理器 ——> 指定认证提供者 。
- userDatailsService 用户授权接口。
- ticketValidator 票据校验器,是cs提供的一个校验器。需要提供一个cas的url地址。
- singleLogoutFilter cas提供的单点登出过滤器。
- requestSingleLogoutFilter spring提供的请求单点登出过滤器,通过该过滤器请求所指向的url地址,简单来说就是完成了一个url的映射功能,将web服务的登出功能url地址映射到cas的登出过滤器url地址。
4. cas.properties配置文件,配置cas的相关url地址
cas_url=http://localhost:8080/cas
service_url=http://localhost:9001
2、 CAS服务端配置
1. 认识cas文件结构和基本配置
编译后的class文件夹结构:
* 静态资源(js,css)存放目录为WEB-INF\classes\static
* WEB-INF\classes\static 目录下存在本身的原有js、css样式,可以进行替换。同时也可以在 WEB-INF\classes\static\themes目录下新建自己的风格,
* html资源(thymeleaf模板)存放目录为WEB-INF\classes\templates
* 主题配置文件存放在WEB-INF\classes,并且命名为[theme_name].properties
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RjY9abBh-1611042125678)(C:\Users\chens\Documents\HwShare\capture_20190701165351112.bmp)]
更多笔记查看