CAS服务器验证成功返回到客户端时,还是返回到登录界面,不能返回到登录成功之后的界面?
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CAS服务器验证成功返回到客户端时,还是返回到登录界面,不能返回到登录成功之后的界面?相关的知识,希望对你有一定的参考价值。
我在学习CAS的时候,根据网上的资料,服务器配置成功了,客户端也和服务器建立信任关系了,就是输入客户端URL,然后跳转到服务器验证,输入用户名和密码,严重成功,跳转到客户端,这时还是跳转到登录界面login.jsp,而不是登录成功后的界面(main.jsp)?
<!-- 用于单点登陆 -->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://localhost:8443/cas/login</param-value>
<!--这里的server是服务端的IP-->
</init-param>
<init-param>
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8888</param-value>
</init-param>
</filter>
<!--负责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>
<!-- casserver产生密钥的时候输入的"姓名(CN)",并且要有这个域名,或者hosts文件中要有定义 -->
<param-value>https://localhost:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://localhost:8888</param-value>
</init-param>
<init-param>
<param-name>useSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS HttpServletRequest WrapperFilter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<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 Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest WrapperFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<!-- CAS 相关配置文件-->
<!-- 单点登出,一定要在最前面 -->
<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>
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!--单点登录 -->
<filter>
<filter-name>CAS Authentication Filter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<!-- CAS login 服务地址-->
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://andy:8443/cas/login</param-value>
</init-param>
<init-param>
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
<!-- 客户端应用服务地址-->
<init-param>
<param-name>serverName</param-name>
<param-value>https://andy:8333</param-value>
</init-param>
</filter>
<!--负责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>https://andy:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://andy:8333</param-value>
</init-param>
<init-param>
<param-name>useSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter>
<filter-name>CAS HttpServletRequest WrapperFilter</filter-name>
<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<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 Authentication Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS HttpServletRequest WrapperFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- CAS 配置文件结束 -->
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
</web-app>
CAS学习笔记—— SERVER登录后用户信息的返回
一旦CAS SERVER验证成功后,我们就会跳转到客户端中去。跳转到客户端去后,大家想一想,客户端总要获取用户信息吧,不然客户端是怎么知道登录的是哪个用户。那么客户端要怎么获取用户信息呢?
其实验证成功,跳转客户端这个过程中,CAS SERVER 会返回登录的相关信息给客户端,客户端只要进行获取,就能知道登录的具体是哪个用户了。不过CAS 默认只返回用户账号给客户端,那么怎么定义CAS SERVER返回的信息呢? 这就是本篇具体讲解的内容了,大家听我慢慢道来。
相关接口
在开始时,我们先了解下有关相关的几个接口
- Credentials
- Principal
- IPersonAttributeDao
- PrincipalResolver
Credentials
Credentials (org.jasig.cas.authentication.Credentials)接口,我们在上一篇其实有使用过,我们当时有用过一个叫 UsernamePasswordCredential 的类,就是实现了Credentials接口。这个接口是用来定义我们登录页上输入的认证信息的,比如用户名、密码、验证码等,可以理解为用户认证的相关凭据。
Principal
Principal (org.jasig.cas.authentication.principal.Principal) 接口,这个主要是用来保存用户认证后的用户信息,信息保存在一个Map中。
IPersonAttributeDao
IPersonAttributeDao (org.jasig.services.persondir.IPersonAttributeDao) 接口,这个是用来定义我们需要返回给客户端相关信息的接口,CAS SERVER 默认有提供许多实现,比如
- LdapPersonAttributeDao :通过查询 LDAP 目录 ,来返回信息
- SingleRowJdbcPersonAttributeDao : 通过JDBC SQL查询,来返回信息
等等,还有许多,大家可以参考源码中的实现,CAS SERVER 提供了各种功能的实现,有时候我们可以直接使用这个现成的就行了。
PrincipalResolver
PrincipalResolver(org.jasig.cas.authentication.principal.PrincipalResolver) 接口,上面有说到 Credentials 是从登录页面上进行获取相关用户信息的。那么认证成功后,怎么把Credentials里面的信息转换到 Principal 中呢,这就是这个接口的作用了。由于认证本身是没有返回用户信息的,只是确定认证是通过还是没有通过。这时还要用到我们上面的IPersonAttributeDao 接口,在这接口中我们就可以定义我们需要返回的信息了。
这接口中有两个方法
- resolve : 解析Credentials中的信息,返回 Principal 接口
- supports : 判断Credentials 是否支持 Principal 协议。
ps: 在3.x版本中没有 PrincipalResolver接口,对应的是CredentialsToPrincipalResolver, PrincipalResolver这个是在4.0版本中加入的,大家要注意。
流程
相关接口讲解后,大家应该对怎么返回信息有个大概的思路了。没错就是实现上面所说的 IPersonAttributeDao 、PrincipalResolver 接口 。下面根据代码讲解下具体的一个流程:
首先打开 deployerConfigContext.xml 文件,看下面的定义:
<!-- | Resolves a principal from a credential using an attribute repository that is configured to resolve | against a deployer-specific store (e.g. LDAP). --> <bean id="primaryPrincipalResolver" class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" > <property name="attributeRepository" ref="attributeRepository" /> </bean> <!-- Bean that defines the attributes that a service may return. This example uses the Stub/Mock version. A real implementation may go against a database or LDAP server. The id should remain "attributeRepository" though. +--> <bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao" p:backingMap-ref="attrRepoBackingMap" /> <util:map id="attrRepoBackingMap"> <entry key="uid" value="uid" /> <entry key="eduPersonAffiliation" value="eduPersonAffiliation" /> <entry key="groupMembership" value="groupMembership" /> </util:map>
//PersonDirectoryPrincipalResolver 部分源码
public final Principal resolve(final Credential credential) { logger.debug("Attempting to resolve a principal..."); String principalId = extractPrincipalId(credential); //extractPrincipalId 方法从credential中抽取id //省略... final IPersonAttributes personAttributes = this.attributeRepository.getPerson(principalId); //根据IPersonAttributeDao 中的getPerson 获取返回的属性 final Map<String, List<Object>> attributes; //最终返回 Principal return new SimplePrincipal(principalId, convertedAttributes); }
具体流程:
1.从上面的deployerConfigContext.xml 配置我们可以看到,CAS 默认配置了一个叫做 PersonDirectoryPrincipalResolver 的类,在 这个类的 resolve 方法中有调用 extractPrincipalId 这个方法,这个方法传入一个 Credentials 类型的参数,默认调用的是Credentials 的getId() 方法,CAS默认是返回用户的userName,即登录账号。不过getId() 这个方法的实现我们可以在上一章中指定的UsernamePasswordCredential 类中自定义,一般是定义成返回用户的userId或者其他唯一键,因为我们如果知道了用户的userId,那么就可以根据这个从数据库中查询中用户的一些具体信息了,进而就可以组成我们需要返回的信息。
2. 继续往下看源码,接着在 PersonDirectoryPrincipalResolver 中有注入一个 attributeRepository 属性,这个就是上面的IPersonAttributeDao 接口,然后在resolve方法中调用了 IPersonAttributeDao 接口 的getPerson方法,还传入了一个参数principalId,其实这个传入的参数就是我们上面 getId() 返回的值。
所以其实我们只要实现我们需要的 IPersonAttributeDao 就可以了。 下面给一个简单的IPersonAttributeDao 例子:
public class BlogStubPersonAttributeDao extends StubPersonAttributeDao { @Override public IPersonAttributes getPerson(String uid) { Map<String, List<Object>> attributes = new HashMap<String, List<Object>>(); attributes.put("userid", Collections.singletonList((Object)uid)); attributes.put("cnblogUsername", Collections.singletonList((Object)"http://www.cnblogs.com/vhua")); attributes.put("cnblogPassword", Collections.singletonList((Object)"123456")); attributes.put("test", Collections.singletonList((Object)"test")); return new AttributeNamedPersonImpl(attributes); } }
这边传入的uid 默认是用户的登录名,我们这边没有做修改,直接用默认的。
这边是只是测试用,所以就直接写死了,实际开发肯定是需要在数据库或者LDAP中进行查询后,然后组装成需要的信息 。
然后在 deployerConfigContext.xml 中修改
<bean id="primaryPrincipalResolver" class="org.jasig.cas.authentication.principal.PersonDirectoryPrincipalResolver" > <property name="attributeRepository" ref="attributeRepository" /> </bean>
<!-- 修改前 --> <bean id="attributeRepository" class="org.jasig.services.persondir.support.StubPersonAttributeDao" p:backingMap-ref="attrRepoBackingMap" /> <util:map id="attrRepoBackingMap"> <entry key="uid" value="uid" /> <entry key="eduPersonAffiliation" value="eduPersonAffiliation" /> <entry key="groupMembership" value="groupMembership" /> </util:map> <!-- 修改前 end-->
<!--修改后--> <bean id="attributeRepository" class="org.jasig.services.persondir.support.BlogStubPersonAttributeDao" /> <!--修改后 end-->
3. 修改完成后,我们还需要在 casServiceValidationSuccess.jspcas-server-webapp\\src\\main\\webapp\\WEB-INF\\view\\jsp\\protocol\\2.0\\casServiceValidationSuccess.jsp)
添加一段代码(下面红色部分):
<cas:serviceResponse xmlns:cas=‘http://www.yale.edu/tp/cas‘> <cas:authenticationSuccess> <cas:user>${fn:escapeXml(assertion.primaryAuthentication.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> <!-- 这段 end-- >
<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>
4. 接下来 在客户端设置信息的接收,我们直接在index.jsp中测试一下:
在Java中可以通过下面的方式获取
AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
Map attributes = principal.getAttributes();
String xxx=attributes .get("xxx");
...
<!DOCTYPE html"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> <title>返回值测试</title> </head> <body> <% request.setCharacterEncoding("UTF-8"); AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal(); Map attributes = principal.getAttributes(); String userid=(String)attributes.get("userid"); String cnblogUsername = (String)attributes.get("cnblogUsername"); String cnblogPassword = (String)attributes.get("cnblogPassword"); String test=(String)attributes.get("test"); %> <div>飞奔的蜗牛博客:返回值演示</div> <ul> <li>userid:<%= userid%></li> <li>username:<%= cnblogUsername%></li> <li>password:<%= cnblogPassword%></li> <li>test:<%= test%></li> </ul> </body> </html>
效果
好了,我们登录运行看看结果。
大家看到没,已经获取成功了,在CAS SERVER那边设置的信息,我们正常获取到了 。大家可以根据业务的需要,返回相关的信息。然后在客户端进行操作。
转自:http://www.cnblogs.com/vhua/p/cas_4.html