首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

yale-cas服务器端深度定做

2014-01-15 
yale-cas服务器端深度定制div //labelc:if test${not empty sessionScope.openIdLocalId}strong

yale-cas服务器端深度定制
<div /> </label> <c:if test="${not empty sessionScope.openIdLocalId}"> <strong>${sessionScope.openIdLocalId}</strong> <input type="hidden" id="loginname" name="loginname" value="${sessionScope.openIdLocalId}" /> </c:if> <c:if test="${empty sessionScope.openIdLocalId}"> <spring:message code="screen.welcome.label.netid.accesskey" var="userNameAccessKey" /> <form:input csscssErrorid="loginname" size="25" tabindex="1" accesskey="${userNameAccessKey}" path="loginname" autocomplete="false" htmlEscape="true" /> </c:if></div>?

在该JSP中name="code"><!--Custom By SGQ 添加登陆字段 --><div /> </label> <spring:message code="screen.welcome.label.custom.accesskey" var="customAccessKey" /> <form:input csscssErrorid="custom" size="25" tabindex="2" path="custom" accesskey="${customAccessKey}" htmlEscape="true" autocomplete="off" /></div>

?

2.用于将参数返回客户端的casServiceValidationSuccess.jsp,在<cas:user>标签下加入如下代码

?

<!-- 解析返回的参数 Custom By SGQ --><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>
?

?

3.在properties中添加字段为casLoginView.jsp添加国际化的显示添加内容

添加相关提示screen.welcome.label.custom和screen.welcome.label.custom.accesskey在

比如

在messages_zh_CN.properties中添加

#Custom By sgq0085screen.welcome.label.custom=\u81ea\u5b9a\u4e49:screen.welcome.label.custom.accesskey=crequired.logingname=\u5fc5\u987b\u5f55\u5165\u7528\u6237\u540d\u3002required.custom=\u81EA\u5B9A\u4E49\u5B57\u6BB
在messages_en.properties文件中添加
#Custom By sgq0085screen.welcome.label.custom=<span name="code">cas.logout.followServiceRedirects=true
?

?

5.login-webflow.xml中修改如下内容

?

<!-- Custom By SGQ--><!-- <var name="credentials" /> --><var name="credentials" /><!-- Custom By SGQ--><binder>    <!-- <binding property="username" /> -->    <binding property="loginname" />    <binding property="password" />    <binding property="custom" /></binder>
?

?

?

2.修改配置文件deployerConfigContext.xml

修改的目的:1.支持页面新增的输入参数;2.实现自定义的认证;3.实现自定义客户端认证后返回的参数;

<?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:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:sec="http://www.springframework.org/schema/security"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd       http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd       http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd       http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd       http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd">    <bean id="authenticationManager" ref="attributeRepository" />                </bean>                <bean />            </list>        </property>        <property name="authenticationHandlers">            <list>                <bean />                <!-- Custom By SGQ 认证的实际位置 -->                <bean />            </list>        </property>    </bean>    <sec:user-service id="userDetailsService">        <sec:user name="@@THIS SHOULD BE REPLACED@@" password="notused" authorities="ROLE_ADMIN" />    </sec:user-service>    <!-- Custom By SGQ 服务器返回值实际封装位置 -->    <bean id="attributeRepository" />    <bean id="serviceRegistryDao" 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" />                    <!-- Custom By SGQ -->                    <property name="ignoreAttributes" value="true" />                </bean>            </list>        </property>    </bean>    <bean id="auditTrailManager" />    <bean id="healthCheckMonitor" p:freeMemoryWarnThreshold="10" />                <bean p:ticketRegistry-ref="ticketRegistry"                    p:serviceTicketCountWarnThreshold="5000" p:sessionCountWarnThreshold="100000" />            </list>        </property>    </bean></beans>

?

package com.gqshao.cas.adaptors;import javax.validation.constraints.NotNull;import org.jasig.cas.authentication.handler.AuthenticationException;import org.jasig.cas.authentication.handler.AuthenticationHandler;import org.jasig.cas.authentication.principal.Credentials;import com.gqshao.cas.principal.MyCredentials;public class MyAuthenticationHandler implements AuthenticationHandler { private static final Class<MyCredentials> DEFAULT_CLASS = MyCredentials.class; @NotNull private Class<?> classToSupport = DEFAULT_CLASS; private boolean supportSubClasses = true; public boolean supports(Credentials credentials) { return credentials != null && (this.classToSupport.equals(credentials.getClass()) || (this.classToSupport .isAssignableFrom(credentials.getClass())) && this.supportSubClasses); } public boolean authenticate(Credentials credentials) throws AuthenticationException { return authenticateLoginnamePasswordInternal((MyCredentials) credentials); } public final void setClassToSupport(final Class<?> classToSupport) { this.classToSupport = classToSupport; } /** * 认证的实际位置 * @param credentials * @return */ private boolean authenticateLoginnamePasswordInternal(MyCredentials credentials) { MyCredentials c = (MyCredentials) credentials; if (c.getLoginname().equals(c.getPassword())) { credentials.setId("select_id_from_table"); return true; } return false; }}

?

(2)com.gqshao.cas.principal.MyCredentials 与登陆参数一一对应

package com.gqshao.cas.principal;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;import org.jasig.cas.authentication.principal.Credentials;public class MyCredentials implements Credentials {    private static final long serialVersionUID = -7008439202352047770L;        private String id;    /** The username. */    @NotNull    @Size(min=1,message = "required.loginname")    private String loginname;    /** The password. */    @NotNull    @Size(min=1, message = "required.password")    private String password;        /** The Custom*/        @NotNull    @Size(min = 1, message = "required.custom")    private String custom;    public String getId() {        return id;    }    public void setId(String id) {        this.id = id;    }    public String getLoginname() {        return loginname;    }    public void setLoginname(String loginname) {        this.loginname = loginname;    }    public String getPassword() {        return password;    }    public void setPassword(String password) {        this.password = password;    }    public String getCustom() {        return custom;    }    public void setCustom(String custom) {        this.custom = custom;    }    public String toString() {        return "[loginname: " + this.loginname + "]";    }    @Override    public boolean equals(final Object o) {        if (this == o) return true;        if (o == null || getClass() != o.getClass()) return false;        MyCredentials that = (MyCredentials) o;        if (password != null ? !password.equals(that.password) : that.password != null) return false;        if (loginname != null ? !loginname.equals(that.loginname) : that.loginname != null) return false;        if (custom != null ? !custom.equals(that.custom) : that.custom != null) return false;        return true;    }    @Override    public int hashCode() {        int result = loginname != null ? loginname.hashCode() : 0;        result = 31 * result + (password != null ? password.hashCode() : 0);        return result;    }}

?

(3).MyCredentialsToPrincipalResolver

package com.gqshao.cas.principal;import org.jasig.cas.authentication.principal.AbstractPersonDirectoryCredentialsToPrincipalResolver;import org.jasig.cas.authentication.principal.Credentials;public class MyCredentialsToPrincipalResolver extends AbstractPersonDirectoryCredentialsToPrincipalResolver {    public boolean supports(Credentials credentials) {        return credentials != null                && MyCredentials.class.isAssignableFrom(credentials                    .getClass());    }        @Override    protected String extractPrincipalId(Credentials credentials) {                final MyCredentials myCredentials = (MyCredentials) credentials;        return myCredentials.getId();    }}

(4)com.gqshao.cas.support.MyPersonImpl 将返回客户端参数封装成POJO

package com.gqshao.cas.support;import java.util.List;import java.util.Map;import org.jasig.services.persondir.IPersonAttributes;import org.jasig.services.persondir.support.BasePersonImpl;public class MyPersonImpl extends BasePersonImpl {    private static final long serialVersionUID = -6468711518798238482L;    public static final String DEFAULT_NAME_ATTRIBUTE = "loginname";    private final String nameAttribute;    public MyPersonImpl(Map<String, List<Object>> attributes) {        super(attributes);        this.nameAttribute = DEFAULT_NAME_ATTRIBUTE;    }    public MyPersonImpl(String nameAttribute, Map<String, List<Object>> attributes) {        super(attributes);        this.nameAttribute = nameAttribute;    }    public MyPersonImpl(IPersonAttributes personAttributes) {        this(personAttributes.getName(), personAttributes.getAttributes());    }    public String getName() {        final Object attributeValue = this.getAttributeValue(this.nameAttribute);        if (attributeValue == null) {            return null;        }        return attributeValue.toString();    }}

?

(5)com.gqshao.cas.support.MyStubPersonAttributeDao 返回客户端的实际位置,这里对中文等进行测试。后续自定义返回有意义的参数。

package com.gqshao.cas.support;import java.util.Collections;import java.util.List;import java.util.Map;import java.util.Set;import org.jasig.services.persondir.IPersonAttributes;import org.jasig.services.persondir.support.StubPersonAttributeDao;import com.google.common.collect.Lists;import com.google.common.collect.Maps;public class MyStubPersonAttributeDao extends StubPersonAttributeDao {        /**     * 服务器返回值实际封装位置     */    @Override    public IPersonAttributes getPerson(String uid) {        Map<String, List<Object>> attributes = Maps.newHashMap();        attributes.put("uid", Collections.singletonList((Object) uid));        attributes.put("custom", Collections.singletonList((Object) "custom_result"));        List<Object> lnarray = Lists.newArrayList();        lnarray.add("admin");        attributes.put("loginname", lnarray);        attributes.put("中文KEY", Collections.singletonList((Object) "中文值"));        for (String key : attributes.keySet()) {            System.out.println(key + " : " + attributes.get(key));        }        MyPersonImpl person = new MyPersonImpl(attributes);        return person;    };    @Override    public Set<IPersonAttributes> getPeopleWithMultivaluedAttributes(Map<String, List<Object>> query) {        return super.getPeopleWithMultivaluedAttributes(query);    }}

?

其实到此为止,CAS服务器已经简单实现完成。可以独立运行了,通过MyAuthenticationHandler.authenticateLoginnamePasswordInternal(Credentials)这里实现自己的认证就可以了,现在只要是用户名和密码相同。即可实现认证。在实际中肯定不是这样。下面我们同时添加数据源、Flyway建库和CXF开放web service接口。

三. 功能扩展和完善1.POM文件中添加依赖,这里使用H2做演示,用Spring JdbcTemplate做数据库做数据库持久层

需要引入

cxf 2.7.7
jackson 2.3.0
tomcat-jdbc 7.0.42

flyway 2.3.1

?

2.添加数据库配置

上面提到过,数据源配置可以配置到/webapp/WEB-INF/cas.properties中,这里采用数据库连接池选用tomcat-jdbc,数据库H2,并用log4jdbc展示SQL,所以内容如下

jdbc.driver=net.sf.log4jdbc.DriverSpyjdbc.url=jdbc:log4jdbc:h2:file:~/.h2/cas;AUTO_SERVER=TRUE;DB_CLOSE_ON_EXIT=TRUE;jdbc.username=sajdbc.password=jdbc.pool.maxIdle=10jdbc.pool.maxActive=50

?

3.添加CXF和Datasource的配置文件和flyway的配置

首先在web.xml中加入cxf的监听

<servlet>    <servlet-name>CXFServlet</servlet-name>    <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class></servlet><servlet-mapping>    <servlet-name>CXFServlet</servlet-name>    <url-pattern>/cxf/*</url-pattern></servlet-mapping>

然后添加数据源和CXF的配置

/src/main/resources/datasource/applicationContext-datasource.xml

<?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:aop="http://www.springframework.org/schema/aop" xmlns:context="http://www.springframework.org/schema/context"    xmlns:p="http://www.springframework.org/schema/p" xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:tx="http://www.springframework.org/schema/tx"    xmlns:jaxrs="http://cxf.apache.org/jaxrs"    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsdhttp://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsdhttp://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsdhttp://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd        http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd">    <description>维护账户信息用数据库连接信息</description>    <!-- 数据源配置,使用应用内的Tomcat JDBC连接池 -->    <bean id="dataSource" destroy-method="close">        <!-- Connection Info -->        <property name="driverClassName" value="${jdbc.driver}" />        <property name="url" value="${jdbc.url}" />        <property name="username" value="${jdbc.username}" />        <property name="password" value="${jdbc.password}" />        <property name="maxActive" value="${jdbc.pool.maxActive}" />        <property name="maxIdle" value="${jdbc.pool.maxIdle}" />        <property name="defaultAutoCommit" value="false" />        <!-- 连接Idle半个小时后超时,每15分钟检查一次 -->        <property name="timeBetweenEvictionRunsMillis" value="900000" />        <property name="minEvictableIdleTimeMillis" value="1800000" />    </bean>    <!-- flyway配置 -->    <bean id="flyway" init-method="migrate">        <property name="dataSource" ref="dataSource" />        <property name="encoding" value="UTF-8" />        <property name="initVersion" value="0" />        <property name="table" value="lcm_schema_version" />        <property name="locations" value="dbmigrate" />        <property name="initOnMigrate" value="true" />    </bean>    <bean id="jdbcTemplate" p:dataSource-ref="dataSource" depends-on="flyway" />    <bean id="transactionManager" />    <bean id="accountService" ref="accountDao" />    </bean>    <bean id="accountDao" ref="jdbcTemplate" />    </bean>    <!-- 通过AOP配置提供事务增强,让AccountService下所有Bean的所有方法拥有事务 -->    <aop:config>        <aop:pointcut id="serviceMethod" expression=" execution(* com.gqshao.account.service..*(..))" />        <aop:advisor pointcut-ref="serviceMethod" advice-ref="txAdvice" />    </aop:config>    <tx:advice id="txAdvice" transaction-manager="transactionManager">        <tx:attributes>            <tx:method name="find*" read-only="true" />            <tx:method name="save" rollback-for="Exception" />        </tx:attributes>    </tx:advice></beans>

?

?

/src/main/resources/webservice/applicationContext-jaxrs-server.xml

<?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:jaxrs="http://cxf.apache.org/jaxrs"    xsi:schemaLocation="http://cxf.apache.org/jaxrs http://cxf.apache.org/schemas/jaxrs.xsd     http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">    <description>Apache CXF的Restful Web Service配置</description>    <!-- jax-rs endpoint定义 -->    <jaxrs:server id="serviceContainer" address="/jaxrs">        <jaxrs:serviceBeans>            <ref bean="accountJaxRsService" />        </jaxrs:serviceBeans>        <jaxrs:providers>            <bean />        </jaxrs:providers>    </jaxrs:server>    <!-- WebService的实现Bean定义 -->    <bean id="accountJaxRsService" ref="accountService" />    </bean></beans>

?

数据库初始化脚本/src/main/resources/dbmigrate/V0_0_1__account_schema.sql

---- 创建报告表-------create table rbac_account(   ID                   CHAR(32)                        not null,   login_name           VARCHAR2(50),   password             VARCHAR2(50),   salt                 VARCHAR2(50),   custom               VARCHAR2(50),   constraint pk_rbac_account primary key (ID));-- Add comments to the table comment on table rbac_account  is '账户表';-- Add comments to the columns comment on column rbac_account.id  is '主键ID';comment on column rbac_account.login_name  is '登录名';comment on column rbac_account.password  is '密码';comment on column rbac_account.salt  is '盐';comment on column rbac_account.custom  is '自定义字段';insert into rbac_account  (id, login_name, password, salt,custom)values  ('ABCDEFGHIJKLMNOPQRSTUVWXYZ012345','admin','8b988cb8b23f880b96575b9fb8b4792b214b3152','fe3d7e30d8e116e2','scope1'); 

?

在/webapp/WEB-INF/deployerConfigContext.xml最后引入上述两个配置

<!-- datasource Custom By SGQ --><import resource="classpath*:/datasource/applicationContext-datasource.xml" /><!-- webservice Custom By SGQ --><import resource="classpath*:/webservice/applicationContext-jaxrs-server.xml" />

?

3.实现类

这里基本上就完成了,实现类的这里把基于Jax-rx的web service接口展示一下

package com.gqshao.account.jaxrs;import javax.ws.rs.GET;import javax.ws.rs.POST;import javax.ws.rs.Path;import javax.ws.rs.PathParam;import javax.ws.rs.Produces;import javax.ws.rs.WebApplicationException;import javax.ws.rs.core.Response;import javax.ws.rs.core.Response.Status;import com.gqshao.account.domain.Account;import com.gqshao.account.domain.ResultDTO;import com.gqshao.account.service.AccountService;import com.gqshao.common.web.MediaTypes;/** * cxf在web.xml侦听/cxf, 在applicationContext.xml里侦听/jaxrx,完整访问路径为 /cxf/jaxrs/account/{loginName}/{custom} */@Path("/account")public class AccountJaxRsService {    private AccountService accountService;    /**     * 判断用户是否存在     * {@link http://localhost:8080/cas/cxf/jaxrs/account/admin/admin}     */    @GET    @Path("/{loginName}/{custom}")    @Produces(MediaTypes.JSON_UTF_8)    public ResultDTO query(@PathParam("loginName") String loginName, @PathParam("custom") String custom) {        Account account = accountService.findByLoginNameAndCustom(loginName, custom);        if (account == null) {            String message = "用户不存在(id:" + loginName + ")";            throw buildException(Status.NOT_FOUND, message);        }        ResultDTO res = new ResultDTO();        res.setSuccess(true);        res.setMsg("用户存在(id:" + loginName + ")");        return res;    }    @POST    @Path("/{loginName}/{password}/{custom}")    @Produces(MediaTypes.JSON_UTF_8)    public ResultDTO save(@PathParam("loginName") String loginName, @PathParam("password") String password,            @PathParam("custom") String custom) {        try {            boolean isSuccess = accountService.save(loginName, password, custom);            ResultDTO res = new ResultDTO();            res.setSuccess(isSuccess);            if (isSuccess) {                res.setMsg("创建" + loginName + "成功");            } else {                res.setMsg("创建" + loginName + "失败");            }            return res;        } catch (Exception e) {            String message = "创建" + loginName + "失败";            throw buildException(Status.EXPECTATION_FAILED, message);        }    }    public void setAccountService(AccountService accountService) {        this.accountService = accountService;    }    private WebApplicationException buildException(Status status, String message) {        return new WebApplicationException(Response.status(status).entity(message)                .type(MediaTypes.TEXT_PLAIN_UTF_8).build());    }}
4.完善认证

还记得 /** * 认证的实际位置 * @param credentials * @return */ private boolean authenticateLoginnamePasswordInternal(MyCredentials credentials) { credentials.setCustom(null); BeanValidators.validateWithException(validator, credentials); Account account = accountService.authenticate(credentials); if (account == null) { return false; } credentials.setId(account.getId()); return true; }

?这里面用到了JSR303去判断credentials属性是否正确,因为前端会做验证,所以这里验证不通过并且抛出异常的都是非正常情况,不用考虑用户界面的友好型。

?

Restful风格的webservice 可以通过进行测试soapUI

转载请注明 :

http://sgq0085.iteye.com/blog/2003190

至此,客户端定制完成。下一篇为服务器端接收参数,并与shiro进行整合。

完整的DEMO在http://download.csdn.net/detail/sgq0085/6847125

再次提醒,服务器端应该部署在SSL认证的服务器上

?

热点排行