4、CAS单点登录源码解析之【用户认证】

前期准备

已经搭建好了集成了CAS客户端的应用系统和CAS服务器

1.应用系统webapp(http://127.0.0.1:8090/webapp/main.do)
2.CAS单点登录服务器端(http://127.0.0.1:8081/cas-server/)

        本次讨论包括CAS单点登录服务器端的部分源码,以及在此基础上进行用户认证二次开发,因此需要修改部分CAS服务器端的源码,源码部分的修改在下面进行讨论。关于CAS客户端、CAS服务器端和CAS单点登出的源码分析,请参考另外三篇文章

CAS客户端:http://blog.csdn.net/dovejing/article/details/44426547
CAS服务器端:http://blog.csdn.net/dovejing/article/details/44523545
CAS单点登出:http://blog.csdn.net/dovejing/article/details/44675647

deployerConfigContext.xml部分代码

[html]  view plain copy
  1. <bean id="dataSource"  class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">  
  2.     <property name="driverClassName" value="com.mysql.jdbc.Driver" />  
  3.     <property name="url" value="jdbc:mysql://127.0.0.1:3306/MASTER?useUnicode=true&characterEncoding=UTF-8" />  
  4.     <property name="username" value="root" />  
  5.     <property name="password" value="root" />  
  6.     <property name="initialSize" value="5"/>  
  7.     <property name="maxActive" value="10" />  
  8.     <property name="maxIdle" value="100" />  
  9.     <property name="maxWait" value="1000" />  
  10.     <property name="timeBetweenEvictionRunsMillis" value="1000"/>  
  11.     <property name="testWhileIdle" value="true"/>  
  12.     <property name="validationQuery" value="select 1"/>  
  13. </bean>  

CAS服务器端的用户认证,默认采用SimpleTestUsernamePasswordAuthenticationHandler类,当输入的用户名和密码相同时,视为认证通过。但实际情况我们会根据需求需要增加自己的用户认证功能,首先在deployerConfigContext.xml配置文件中增加数据源的配置信息(mysql)。

deployerConfigContext.xml部分代码

[html]  view plain copy
  1. <bean id="authenticationManager" class="org.jasig.cas.authentication.AuthenticationManagerImpl">    
  2.     <property name="credentialsToPrincipalResolvers">  
  3.         <list>  
  4.             <bean class="org.jasig.cas.authentication.principal.UsernamePasswordCredentialsToPrincipalResolver" >  
  5.                 <property name="attributeRepository" ref="attributeRepository" />  
  6.             </bean>  
  7.   
  8.             <bean class="org.jasig.cas.authentication.principal.HttpBasedServiceCredentialsToPrincipalResolver" />  
  9.         </list>  
  10.     </property>  
  11.   
  12.     <property name="authenticationHandlers">  
  13.         <list>  
  14.             <bean class="org.jasig.cas.authentication.handler.support.HttpBasedServiceCredentialsAuthenticationHandler"  
  15.                 p:httpClient-ref="httpClient" />  
  16.               
  17.             <!-- 注解默认的认证方式 -->  
  18.             <!--bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler"/-->  
  19.             <!-- 此处为增加部分 start -->  
  20.             <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">  
  21.                 <property name="sql" value="SELECT PASSWORD FROM USER"/>  
  22.                 <!-- 引用数据源 -->  
  23.                 <property name="dataSource" ref="dataSource" />  
  24.                 <!-- 定义MD5的加密方式 -->  
  25.                 <property name="passwordEncoder">  
  26.                     <bean class="org.jasig.cas.authentication.handler.ext.MD5PasswordEncoder"></bean>  
  27.                 </property>  
  28.             </bean>  
  29.             <!-- 此处为增加部分 end -->  
  30.         </list>  
  31.     </property>  
  32. </bean>  
  33. <!-- 注解默认的属性  
  34. <bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao">  
  35.     <property name="backingMap">  
  36.         <map>  
  37.             <entry key="uid" value="uid" />  
  38.             <entry key="eduPersonAffiliation" value="eduPersonAffiliation" />   
  39.             <entry key="groupMembership" value="groupMembership" />  
  40.         </map>  
  41.     </property>  
  42. </bean>  
  43. -->  
  44. <!-- 此处为增加部分 start -->  
  45. <bean  class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao" id="attributeRepository">  
  46.     <constructor-arg index="0" ref="dataSource"/>  
  47.     <constructor-arg index="1" value="SELECT * FROM USER WHERE {0}"/>  
  48.     <property name="queryAttributeMapping">  
  49.         <map>  
  50.             <!-- key对应登录信息, vlaue对应数据库字段 -->  
  51.             <entry key="username" value="LOGIN_NAME"/>  
  52.         </map>  
  53.     </property>  
  54.     <property name="resultAttributeMapping">  
  55.         <map>  
  56.             <!-- key对应数据库字段  value对应attribute中的key -->  
  57.             <entry key="mobile" value="mobile"/>  
  58.             <entry key="email" value="email"/>  
  59.         </map>  
  60.     </property>  
  61. </bean>  
  62. <!-- 此处为增加部分 end -->  
  63.   
  64. <bean id="serviceRegistryDao" class="com.uws.uaserver.services.InMemoryServiceRegistryDaoImpl">  
  65.     <property name="registeredServices"> -->  
  66.         <!-- 注解默认的配置  
  67.         <list>  
  68.             <bean class="org.jasig.cas.services.RegexRegisteredService">  
  69.                 <property name="id" value="0" />  
  70.                 <property name="name" value="HTTP and IMAP" />  
  71.                 <property name="description" value="Allows HTTP(S) and IMAP(S) protocols" />  
  72.                 <property name="serviceId" value="^(https?|imaps?)://.*" />  
  73.                 <property name="evaluationOrder" value="10000001" />  
  74.             </bean>  
  75.   
  76.             <bean class="org.jasig.cas.services.RegexRegisteredService">  
  77.                 <property name="id" value="1" />  
  78.                 <property name="name" value="HTTP and IMAP on example.com" />  
  79.                 <property name="description" value="Allows HTTP(S) and IMAP(S) protocols on example.com" />  
  80.                 <property name="serviceId" value="^(https?|imaps?)://([A-Za-z0-9_-]+\.)*example\.com/.*" />  
  81.                 <property name="evaluationOrder" value="0" />  
  82.             </bean>  
  83.         </list>  
  84.         -->  
  85.     </property>  
  86. </bean>  

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

[html]  view plain copy
  1. <%@ page session="false" %>  
  2. <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  
  3. <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>  
  4. <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>  
  5.     <cas:authenticationSuccess>  
  6.         <cas:user>${fn:escapeXml(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.id)}</cas:user>  
  7.         <!-- 增加部分 start -->  
  8.         <c:if test="${fn:length(assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes) > 0}">  
  9.             <cas:attributes>  
  10.                 <c:forEach var="attr" items="${assertion.chainedAuthentications[fn:length(assertion.chainedAuthentications)-1].principal.attributes}">  
  11.                     <cas:${fn:escapeXml(attr.key)}>${fn:escapeXml(attr.value)}</cas:${fn:escapeXml(attr.key)}>  
  12.                 </c:forEach>  
  13.             </cas:attributes>  
  14.         </c:if>  
  15.         <!-- 增加部分 end -->  
  16. <c:if test="${not empty pgtIou}">  
  17.         <cas:proxyGrantingTicket>${pgtIou}</cas:proxyGrantingTicket>  
  18. </c:if>  
  19. <c:if test="${fn:length(assertion.chainedAuthentications) > 1}">  
  20.         <cas:proxies>  
  21. <c:forEach var="proxy" items="${assertion.chainedAuthentications}" varStatus="loopStatus" begin="0" end="${fn:length(assertion.chainedAuthentications)-2}" step="1">  
  22.             <cas:proxy>${fn:escapeXml(proxy.principal.id)}</cas:proxy>  
  23. </c:forEach>  
  24.         </cas:proxies>  
  25. </c:if>  
  26.     </cas:authenticationSuccess>  
  27. </cas:serviceResponse>  

修改deployerConfigContext.xml配置文件,注解默认的认证配置和默认的attributeRepository配置信息,增加用户自己的认证配置和attributeRepository配置。

  1. 初始化QueryDatabaseAuthenticationHandler类的sql属性(SELECT PASSWORD FROM USER),引用数据源dataSource(mysql数据源),初始化passwordEncode属性(MD5PasswordEncoderr密码加密类)。此处的sql属性只是一个简单的查询语句,实际应用中可以定义一个复杂的SQL语句。
  2. 增加自己的attributeRepository配置。dataScore和SELECT * FROM USER WHERE {0}为SingleRowJdbcPersonAttributeDao构造方法的两个参数,queryAttributeMapping是为了组装SQL(SELECT * FROM USER WHERE LOGIN_NAME=username),resultAttributeMapping是SQL查询返回结果属性。

修改casServiceValidationSuccess.jsp页面,由于默认的页面只有user的信息,并没有attributes的信息,因此我们需要增加该信息,本文中只增加了mobile和email,实际应用中可根据需要增加多个属性信息。

该页面最终的返回结果如下:

[html]  view plain copy
  1. <cas:serviceResponse xmlns:cas='http://www.yale.edu/tp/cas'>  
  2.     <cas:authenticationSuccess>  
  3.         <cas:user>system</cas:user>  
  4.         <cas:attributes>  
  5.             <cas:mobile>13688888888</cas:mobile>  
  6.             <cas:email>xxx@master.com</cas:email>  
  7.         </cas:attributes>  
  8.     </cas:authenticationSuccess>  
  9. </cas:serviceResponse>  

客户端获取用户认证的信息的代码

[java]  view plain copy
  1. AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();    
  2. String loginName = principal.getName();  
  3. Map<String, Object> attributes = principal.getAttributes();    
  4. if (attributes != null) {   
  5.     String mobile = attributes.get("mobile"));    
  6.     String email = attributes.get("email"));     
  7. }  

QueryDatabaseAuthenticationHandler的authenticateUsernamePasswordInternal方法

[java]  view plain copy
  1. protected final boolean authenticateUsernamePasswordInternal(final UsernamePasswordCredentials credentials)  
  2.     throws AuthenticationException {  
  3.     //用户名  
  4.     final String username = getPrincipalNameTransformer().transform(credentials.getUsername());  
  5.     //密码  
  6.     final String password = credentials.getPassword();  
  7.   
  8.     Map resultMap = null;  
  9.     try {  
  10.         resultMap = getJdbcTemplate().queryForMap(this.sql, new Object[] { username });  
  11.         String dbPassword = (resultMap.get("PASSWORD") == null) ? ""  
  12.                 : resultMap.get("PASSWORD").toString();  
  13.         String encryptedPassword = getPasswordEncoder().encode(password);  
  14.               
  15.         //判断密码是否相等  
  16.         return dbPassword.equals(encryptedPassword);  
  17.     } catch (IncorrectResultSizeDataAccessException e) {  
  18.     }  
  19.     return false;  
  20. }  
QueryDatabaseAuthenticationHandler的authenticateUsernamePasswordInternal方法,要做的就是获取用户输入的用户名和密码,用配置文件中配置的加密方式(MD5PasswordEncoder类)进行加密,用加密后的密码encryptedPassword和用SQL语句在数据库中查询的密码(dbPassword)进行对比,并返回结果。

MD5PasswordEncoder类

[java]  view plain copy
  1. public class MD5PasswordEncoder implements PasswordEncoder {  
  2.     public String encode(String password) {  
  3.         try {  
  4.             return MD5.crypt(password);//MD5加密  
  5.         } catch (NoSuchAlgorithmException e) {  
  6.             e.printStackTrace();  
  7.         }  
  8.         return null;  
  9.     }  
  10. }  

MD5PasswordEncoder类,要做的就是对用户输入的密码进行加密。此类是新增加的类,用户可以增加任何有加密逻辑的类,但此类必须实现org.jasig.cas.authentication.handler.PasswordEncoder接口,并实现String encode(String password)方法

至此,CAS用户认证的修改已经完成。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值