CAS 实现单点登录(SSO)返回更多用户信息(五)

配置转换器返回更多用户信息

cas server登录成功后,默认只能从cas server得到用户名。但程序中也可能遇到需要得到更多如姓名,手机号,email等更多用户信息的情况。

cas client拿到用户名后再到数据库中查询,的确可以得到关于该用户的更多信息。

但是如果用户登录成功后,直接从cas server返回给cas client用户的详细信息,这也是一个不错的做法。这个好处,尤其是在分布式中得以彰显,cas server可以把用户信息传递给各个应用系统,如果是上面那种做法,那么各个系统得到用户名后,都得去数据库中查询一遍,无疑是一件重复性工作。

 

一、首先需要配置属性attributeRepository

首先,你需要到WEB-INF目录找到 deployerConfigContext.xml文件,同时配置 attributeRepository 如下:

<bean  class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao" id="attributeRepository">
        <constructor-arg index="0" ref="dataSource"/>
        <constructor-arg index="1" value="select * from t_user where {0}"/>
        <property name="queryAttributeMapping">
            <map>
				<!--这里的key需写username和登录页面一致,value对应数据库用户名字段-->
                <entry key="username" value="loginname"/> 
                 
            </map>
        </property>
        <property name="resultAttributeMapping">
            <map>
				<!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值-->  
                <entry key="Id" value="Id"/>                
                <entry key="password" value="password"/>
                <entry key="age" value="age"/> 
            </map>
        </property>
       <!--  <property name="queryType">
			<value>OR</value>
      </property> -->
        
    </bean>

其中:

切记:查询出来的字段名中间不能使用 _ (下划线),否则获取不到数据,如 cell_phone 需要 设置别名为 cellPhone.

queryAttributeMapping是组装sql用的查询条件属性,上述配置后,结合封装成查询sql就是 select* from userinfo where loginname=#username#

resultAttributeMappingsql执行完毕后返回的结构属性, key对应数据库字段,value对应客户端获取参数。

如果要组装多个查询条件,需要加上下面这个,默认为AND

<property name="queryType">

<value>OR</value>

     </property>  


二、配置用户认证凭据转化的解析器

也是在 deployerConfigContext.xml中,为 UsernamePasswordCredentialsToPrincipalResolver注入 attributeRepository,那么 attributeRepository就会被触发并通过此类进行解析,红色为新添部分。


<property name="credentialsToPrincipalResolvers">
			<list>
				<bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >
					<property name="attributeRepository" ref="attributeRepository" />			
				</bean>
				<bean
					class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />
			</list>
		</property>
 

三、修改 deployerConfigContext.xml

中的 org.jasig.cas.services.InMemoryServiceRegistryDaoImpl属性 registeredServices

修改 registeredServices  列表中的每个协议中的 allowedAttributes属性的值。列出的每个值,在客户端就可以访问了


<bean
		id="serviceRegistryDao"
        class="org.jasig.cas.services.InMemoryServiceRegistryDaoImpl">
            <property name="registeredServices">
                <list>
                    <bean class="org.jasig.cas.services.RegexRegisteredService">
                        <property name="id" value="0" />
                        <property name="name" value="HTTP and IMAP" />
                        <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" />
                        <property name="serviceId" value="^(https?|imaps?)://.*" />
                        <property name="evaluationOrder" value="10000001" />						
						
						   <property name="allowedAttributes">
                                <list>
                                        <value>Id</value>
                                        <value>password</value>
                                         <value>age</value> 
                                </list>
                        </property>

                    </bean>

此步骤灰常重要,可以看看 org.jasig.cas.services.RegexRegisteredService的源码,其中的 allowedAttributes是关键

【提示】网上说此bean中的ignoreAttributes属性默认是不添加用户信息,查看了 CAS 3.5.2版本的 AbstractRegisteredService 源码后,发现其默认值就是 false,即:添加属性后,客户端就可见了

 

四、修改casServiceValidationSuccess.jsp

WEB-INF/view/jsp/protocol/2.0/casServiceValidationSuccess.jsp

server验证成功后,这个页面负责生成与客户端交互的xml信息,在默认的casServiceValidationSuccess.jsp中,只包括用户名,并不提供其他的属性信息,因此需要对页面进行扩展,如下,红色为新添加部分 


<cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>
  <cas:authenticationSuccess>
<cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>

<c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">
            <cas:attributes>
                <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">
                    <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>
                </c:forEach>
            </cas:attributes>
        </c:if>

<c:if test="${not empty pgtIou}">
   <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>
</c:if>
<c:if test="${fn:length(assertion.chainedAuthentications) > 1}">
<cas:proxies>
<c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">
    <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>
</c:forEach>
</cas:proxies>
</c:if>
 </cas:authenticationSuccess>
</cas:serviceResponse>

通过完成上面四个步骤的配置后,CAS Server端的工作就完成了,那么如何在客户端获取这些信息呢?下面进行说明:

 

cas client获取用户信息:

AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
Map attributes = principal.getAttributes();

String email=attributes .get("age");


补充:

 

cas_client项目结构:




web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>cas_client</display-name>
  <welcome-file-list>
    <welcome-file>userInfoView.jsp</welcome-file>
  </welcome-file-list>
  
 <!-- ======================== 单点登录开始 ======================== -->
                 <!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置-->
                <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>CAS Filter</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</param-value>
                        </init-param>
                        <init-param>
                                <param-name>serverName</param-name>
                                <param-value>http://localhost:18080</param-value>
                        </init-param>
                </filter>
                <filter-mapping>
                        <filter-name>CAS Filter</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:18080</param-value>
                        </init-param>
                </filter>
                <filter-mapping>
                        <filter-name>CAS Validation Filter</filter-name>
                        <url-pattern>/*</url-pattern>
                </filter-mapping>
                
			
               <!--   该过滤器负责实现HttpServletRequest请求的包裹, -->
               <!--  比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。 -->
                

                <filter>
                        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
                        <filter-class>
                                org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
                </filter>
                <filter-mapping>
                        <filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
                        <url-pattern>/*</url-pattern>
                </filter-mapping>
                

             <!--  该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。 -->
             <!--  比如AssertionHolder.getAssertion().getPrincipal().getName()。根据客户端获取的方式可以选择使用这两种 -->
                

               <!--  <filter>
                        <filter-name>CAS Assertion Thread Local Filter</filter-name>
                        <filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
                </filter>
                <filter-mapping>
                        <filter-name>CAS Assertion Thread Local Filter</filter-name>
                        <url-pattern>/*</url-pattern>
                </filter-mapping> -->
                
<!-- ======================== 单点登录结束 ======================== -->

   <servlet>
       <servlet-name>HelloWorldExample</servlet-name>
       <servlet-class>com.tgb.cas.client.HelloWorldExample</servlet-class>
   </servlet>
   
   <servlet-mapping>
      <servlet-name>HelloWorldExample</servlet-name>
      <url-pattern>/servlet/HelloWorldExample</url-pattern>
  </servlet-mapping>
</web-app>


HelloWorldExample:

public class HelloWorldExample extends HttpServlet {
	private static final long serialVersionUID = 1L;

	public void doGet(HttpServletRequest request, HttpServletResponse response)
			throws IOException, ServletException {
		response.setContentType("text/html");
		PrintWriter out = response.getWriter();

		out.println("<html>");
		out.println("<head>");

		String title = "Hello";

		out.println("<title>" + title + "</title>");
		out.println("</head>");
		out.println("<body bgcolor=\"white\">");


		out.println("<a href=\"../helloworld.html\">");
		out.println("<img src=\"../images/code.gif\" height=24 "
				+ "width=24 align=right border=0 alt=\"view code\"></a>");
		out.println("<a href=\"../index.html\">");
		out.println("<img src=\"../images/return.gif\" height=24 "
				+ "width=24 align=right border=0 alt=\"return\"></a>");
		out.println("<h1>" + title + "</h1>");
		//以下是两种获取用户信息的两种方式,分别与Web.XML中的配置相对应,大家结合理解
		
		// 通过 CAS HttpServletRequest Wrapper Filter 获取用户信息
		String userNameString = request.getRemoteUser();
		
		AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
		
		if (null != principal) {
			Map<String, Object> attMap = principal.getAttributes();
			out.println(" Log | getAttributes Map size = " + attMap.size() + "<br>");
			for (Entry<String, Object> entry : attMap.entrySet()) {
				out.println("     | " + entry.getKey() + "=:" + entry.getValue() + "<br>");
			}		
			String username = null;
			out.print(" Log | UserName:");
			if (null != principal) {
				username = principal.getName();
				out.println("<span style='color:red;'>" + username + "</span><br>");
			}
		}
		
		
		
		// 通过CAS Assertion Thread Local Filter  获取用户信息,共两种方式
//		Assertion assertion = (Assertion) request.getSession().getAttribute(
//				AbstractCasFilter.CONST_CAS_ASSERTION);
//		if (null != assertion) {
//			
//			Map<String, Object> attMap = assertion.getPrincipal().getAttributes();
//			out.println(" Log | getAttributes Map size = " + attMap.size() + "<br>");
//			for (Entry<String, Object> entry : attMap.entrySet()) {
//				out.println("     | " + entry.getKey() + "=:" + entry.getValue() + "<br>");
//			}
//			
//			AttributePrincipal principal = assertion.getPrincipal();
//			// AttributePrincipal principal = (AttributePrincipal) request
//			// .getUserPrincipal();
//			String username = null;
//			out.print(" Log | UserName:");
//			if (null != principal) {
//				username = principal.getName();
//				out.println("<span style='color:red;'>" + username + "</span><br>");
//			}
//		}

		out.println("</body>");
		out.println("</html>");
	}
}

userInfoView.jsp(未使用):

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
	<a href="servlet/HelloWorldExample">获取Server端用户信息</a>
	<br>
	<a href="http://localhost:8080/cas/logout?service=http://localhost:18080/cas_client/servlet/HelloWorldExample">单点退出</a>
</body>
</html>

效果:


访问:http://localhost:18080/cas_client/servlet/HelloWorldExample




附:



其中cas服务端对应的代码是官网中提供的cas-server-webapp-3.5.2.war,而cas_client客户端代码是我们自己编写的,参照tomcat中的example项目。

 

 

总结:

     CAS返回更多用户信息这方面的文章有很多,在这里我再次进行总结学习也是为了梳理自己的知识,让自己加深理解。以上只是一个简单的知识点,大家理解就好,接下来会结合Spring进行学习。



 


  • 5
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 21
    评论
### 回答1: (SSO)的优势有哪些? CAS方式实现SSO的优势包括:1)可以有效地减少用户登录次数;2)可以提供安全的认证服务,保护用户的账号安全;3)可以支持多个应用系统,减少用户登录的麻烦;4)可以跨域访问,支持用户跨域登录。 ### 回答2: CAS(Central Authentication Serivce)是一种单点登录(Single Sign-On,简称SSO)的解决方案。它通过在一个系统中进行身份验证,然后将凭证(ticket)分发给其他系统,以便在这些系统中实现单点登录。 在CAS方式中,有三个主要角色:CAS Server、CAS Client和用户CAS Server是用于身份验证和票证的分发中心,CAS Client是需要访问的应用程序,用户是需要登录并访问这些应用程序的人。 实现CAS单点登录的过程如下: 1. 用户访问一个CAS Client应用程序,并尚未登录。 2. CAS Client检测到用户登录,将用户重定向到CAS Server的登录页面。 3. 用户CAS Server登录页面上输入用户名和密码进行身份验证。 4. CAS Server验证用户的凭证,如果身份验证成功,CAS Server会生成一个票证(ticket)并将其存储。 5. CAS Server将用户重定向回原始CAS Client应用程序,并附带这个生成的票证。 6. CAS Client应用程序接收到票证后,它会将该票证发送给CAS Server进行验证。 7. CAS Server验证票证的有效性,如果有效,CAS Server会生成一个ST(Service Ticket),并将其发送给CAS Client应用程序。 8. CAS Client应用程序再次发送ST给CAS Server,CAS Server验证ST的有效性。 9. 如果验证成功,CAS Server会告诉CAS Client应用程序用户已经成功登录,并且CAS Client应用程序可以在当前会话中使用用户的身份。 通过CAS方式实现单点登录有以下优点: 1. 提高用户体验:用户只需登录一次,就可以访问所有CAS Client应用程序,不需要多次身份验证。 2. 简化用户管理:CAS Server负责用户身份验证和管理,避免了在每个应用程序中独立管理用户。 3. 提高安全性:通过票证(ticket)的方式,CAS Server负责身份验证和票证的生成,可以减少密码泄露的风险。 总之,CAS方式实现单点登录,为用户带来了便利和安全性,并简化了应用程序的用户管理。 ### 回答3: CAS(Central Authentication Service)是一种实现单点登录SSO)的方式。它采用了基于票据的认证机制,使用户只需要登录一次,就能够访问多个相互信任的应用系统。 CAS的工作原理如下: 1. 用户访问需要进行登录认证的应用系统,应用系统检测到用户登录,将用户重定向到CAS服务器。 2. CAS服务器收到重定向请求后,生成一个唯一的票据(ticket),并将该票据以重定向方式发送给用户的浏览器。 3. 用户的浏览器将携带票据重定向回原先的应用系统。 4. 应用系统接收到票据后,将该票据发送给CAS服务器进行验证。 5. CAS服务器验证票据的有效性,如果票据有效,则返回用户登录凭证给应用系统。 6. 应用系统使用该凭证进行用户登录操作,并为用户生成相应的会话信息。 7. 用户可以在该应用系统中进行操作,直到会话过期或用户主动注销。 8. 如果用户访问其他需要进行认证的应用系统,重复以上步骤2-7,但在步骤4中,CAS服务器验证票据的有效性后直接返回凭证给应用系统,无需用户再次登录。 通过CAS方式实现单点登录可以实现用户的统一认证和授权管理,提高用户的使用便捷性和体验度。CAS还可以支持多种认证方式,如用户名/密码、证书、短信验证码等,以满足不同应用系统的需求。此外,CAS还提供了管理中心,可以对用户进行集中管理和授权管理,提供灵活的权限控制和用户管理功能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值