SSO单点登录

1、单点登录

 登录,也就是用户的一次登录能得到其他所有系统的信任。单点登录在大型网站里使用得非常频繁,例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协作,如果每个子系统都需要用户认证,不仅用户会疯掉,各个子系统也会为这种重复认证授权的逻辑搞疯掉。实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他系统如何验证这个信任的有效性,因此要点也就是以下几个:

  • 存储信任
  • 验证信任

 一般来说,大型应用会把授权的逻辑与用户信息的相关逻辑独立成一个应用,称为用户中心。用户中心不处理业务逻辑,只是处理用户信息的管理以及授权给第三方应用。第三方应用需要登录的时候,把用户的登录请求转发给用户中心进行处理,用户处理完毕后返回凭证,第三方应用验证凭证,通过后就登录用户。

2、CAS

 CAS = Central Authentication Service,中央认证服务,是一款不错的针对Web应用的单点登录框架。SSO的解决方案很多,其中应用最为广泛的是CAS。
 CAS从结构上看包括两部分,CAS Server为需要独立部署的Web应用,CAS Client为非常多的客户端提供支持,这个客户端指单点登录系统中的各个Web应用。
CAS 原理和协议 
CAS Server 需要独立部署,主要负责对用户的认证工作; 
CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图是 CAS 最基本的协议过程:


CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket(服务票据,由 CAS Server发出用于标识目标服务) 
        如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。
        如果有,则说明当前用户已经登录,直接访问目的资源地址。  
用户输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(CAS会话标识)  
       CAS Client 在拿到 Service 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份(核实)合适,以确保 Service Ticket 的合法性。 
      在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透明的,时序图如下所示。


3、CAS+shiro+Spring集成

Spring下使用shiro+cas配置单点登录,多个系统之间的访问,每次只需要登录一次。

系统模块:

  • cas:单点登录模块,字节下载cas server webapp war部署到tomcat的webapps下
  • spring-node-1:应用1
  • spring-node-2:应用2

系统部署架构图如下:


下载cas server webapp war部署到tomcat的webapps,作为认证中心,采用的是查数据库的方式来校验用户身份的,在cas/WEB-INF/deployerConfigContext.xml中第135行构建了这个类型。

<!-- 设置密码的加密方式,这里使用的是MD5加密 -->
    <bean id="passwordEncoder"
      class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder"
      c:encodingAlgorithm="MD5"
      p:characterEncoding="UTF-8" />

  <!-- 通过数据库验证身份,这个得自己去实现 -->
    <bean id="primaryAuthenticationHandler"
      class="com.distinct.cas.jdbc.QueryDatabaseAuthenticationHandler"
      p:dataSource-ref="dataSource"
      p:passwordEncoder-ref="passwordEncoder"
      p:sql="select password from t_user where account=? and status = 'active'" />
      
  <!-- 设置数据源 -->
     <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
          <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
          <property name="url" value="jdbc:mysql://127.0.0.1:3306/db_test?useUnicode=true&characterEncoding=utf8"></property>
          <property name="username" value="root"></property>
          <property name="password" value="123456"></property>  
  </bean>
其中QueryDatabaseAuthenticationHandler这个类是自定义构建的,在cas/WEB-INF/lib/cas-jdbc-1.0.0.jar里面,有兴趣的同学可以发编译看下,关于几个属性的说明:
dataSource: 数据源,配置MySQL的连接信息
passwordEncoder: 加密方式,这里用的是MD5
sql: sql查询语句,这个语句就是根据用户输入的账号查询其密码
启动本地tomcat访问登录页,输入用户名及密码:



应用系统采用shiro做权限控制,并且跟cas集成,使用shiro自带的shiro-cas作为sso-client,shiro配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:cache="http://www.springframework.org/schema/cache"
	xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
         http://www.springframework.org/schema/cache 
         http://www.springframework.org/schema/cache/spring-cache-4.0.xsd
         http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<!-- Shiro Filter -->
	<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
		<property name="securityManager" ref="securityManager" />
		<!-- 设定用户的登录链接,这里为cas登录页面的链接地址可配置回调地址 -->
		<property name="loginUrl" value="${shiro.loginUrl}" />
		<property name="filters">
			<map>
				<!-- 添加casFilter到shiroFilter -->
				<entry key="casFilter" value-ref="casFilter" />
				<entry key="logoutFilter" value-ref="logoutFilter" />
			</map>
		</property>
		<property name="filterChainDefinitions">
			<value>
				/shiro-cas = casFilter
				/logout = logoutFilter
				/users/** = user
			</value>
		</property>
	</bean>

	<bean id="casFilter" class="org.apache.shiro.cas.CasFilter">
		<!-- 配置验证错误时的失败页面 -->
		<property name="failureUrl" value="${shiro.failureUrl}" />
		<property name="successUrl" value="${shiro.successUrl}" />
	</bean>

	<bean id="logoutFilter" class="org.apache.shiro.web.filter.authc.LogoutFilter">
		<!-- 配置验证错误时的失败页面 -->
		<property name="redirectUrl" value="${shiro.logoutUrl}" />
	</bean>

	<bean id="casRealm" class="com.spring.mybatis.realm.UserRealm">
		<!-- 认证通过后的默认角色 -->
		<property name="defaultRoles" value="ROLE_USER" />
		<!-- cas服务端地址前缀 -->
		<property name="casServerUrlPrefix" value="${shiro.cas.serverUrlPrefix}" />
		<!-- 应用服务地址,用来接收cas服务端票据 -->
		<property name="casService" value="${shiro.cas.service}" />
	</bean>

	<!-- Shiro's main business-tier object for web-enabled applications -->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<!-- <property name="sessionManager" ref="sessionManager" /> -->
		<property name="subjectFactory" ref="casSubjectFactory"></property>
		<property name="realm" ref="casRealm" />
	</bean>

	<bean id="casSubjectFactory" class="org.apache.shiro.cas.CasSubjectFactory"></bean>



	<bean
		class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>


	<!-- <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> 
		<property name="globalSessionTimeout" value="3600000" /> <property name="sessionDAO" 
		ref="sessionDAO" /> </bean> -->

	<!-- <bean id="sessionDAO" class="com.distinct.web.session.redis.RedisSessionDAO"> 
		<property name="sessionTimeout" value="1800000" /> <property name="redisManager" 
		ref="redisManager" /> </bean> -->

	<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>

	<bean
		class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
		<property name="staticMethod"
			value="org.apache.shiro.SecurityUtils.setSecurityManager"></property>
		<property name="arguments" ref="securityManager"></property>
	</bean>

</beans>
参数配置:
#localhost
shiro.loginUrl=http://127.0.0.1:8080/cas/login?service=http://127.0.0.1:8081/node1/shiro-cas

shiro.logoutUrl=http://127.0.0.1:8080/cas/logout?service=http://127.0.0.1:8081/node1/shiro-cas

shiro.cas.serverUrlPrefix=http://127.0.0.1:8080/cas

shiro.cas.service=http://127.0.0.1:8081/node1/shiro-cas

shiro.failureUrl=/users/loginSuccess

shiro.successUrl=/users/loginSuccess

node2的配置同上类似只是改了一下参数。启动node1,首先拦截访问请求,发现没有登录,跳转到登录地址,登录地址以上配置的是SSO认证中心,登录中心返回登录页,用户输入用户名及密码提交到登录中心验证,验证通过,跳转到应用的处理接收tokecn的Service地址。拦截器CASFilter拦截验证token,再去认证中心核实,通过则创建session建立连接。




用户登录成功之后,node2不用登录即可直接访问了。


参考:

https://www.cnblogs.com/ywlaker/p/6113927.html

https://www.cnblogs.com/coderhuang/p/5897444.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值