月度归档: 2013 年 7 月

  • CAS Server3.5.2 + Client3.2.1 单点登录(无证书全攻略)

    配置环境:
    JDK 1.6 + TOMCAT 6
    Yale CAS Server3.5.2 + Client3.2.1

    工作准备:
    到 http://www.jasig.org/cas 中下载对应版本的 服务器端cas-server-3.5.2-release.zip 和 客户端cas-client-3.2.1-release.zip

    一、尝试运行CAS服务器端
    解压cas-server-3.5.2-release.zip, 在里面的moudles文件夹里有个cas-server-webapp-3.5.2.war文件, 这个就是服务器的所有文件, 解压, 设置tomcat的server.xml把该文件夹添加对应的虚拟目录, 我们以 http://localhost:8080/cas 为例,登录 http://localhost:8080/cas 后你们可以看到登录界面,便于测试,CAS默认输入相同的账号跟密码即可通过登录验证。

    二、配置CAS服务端,使其读取mysql数据库对应的数据进行登录判断

    打开CAS的/WEB-INF/deployerConfigContext.xml,找到以下代码并注释掉,取消掉原来的用于测试的简单验证

    <bean class="org.jasig.cas.authentication.handler.support.SimpleTestUsernamePasswordAuthenticationHandler" />

    换成以下的验证方式

    <bean class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler">
    	<property name="dataSource" ref="dataSource" />
    	<property name="sql" value="SELECT password FROM account WHERE email=?" />
    </bean>

    并配置对应的数据源(添加bean):

    	<!-- 配置数据源 -->
    	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
    		<property name="driverClassName">
    			<value>com.mysql.jdbc.Driver</value>
    		</property>
    		<property name="url">
    			<value>jdbc:mysql://localhost:3306/sway_account?useUnicode=true&amp;characterEncoding=utf-8</value>
    		</property>
    		<property name="username">
    			<value>root</value>
    		</property>
    		<property name="password">
    			<value></value>
    		</property>
    	</bean>

     

    三、配置CAS客户端

    新建一个tomcat虚拟目录,我们以 http://localhost:8080/test 为例,并且确保里面有一个可访问的文件(我们这里以index.jsp为例),解压cas-client-3.2.1-release.zip,在里面modules里面找到cas-client-core-3.2.1.jar以及commons-logging-1.1.jar文件,复制到 http://localhost:8080/test 项目里面的 WEB-INF/lib 文件夹里面,然后修改里面的web.xml文件,添加以下过滤器:

    <?xml version="1.0" encoding="UTF-8"?>
    <web-app id="WebApp_ID" version="3.0"
    	xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    	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_3_0.xsd">
    
    	<welcome-file-list>
    		<welcome-file>index.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>CASFilter</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/login</param-value>
    			<!--这里的server是服务端的IP -->
    		</init-param>
    		<init-param>
    			<param-name>serverName</param-name>
    			<param-value>http://localhost:8080/</param-value>
    		</init-param>
    	</filter>
    	<filter-mapping>
    		<filter-name>CASFilter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
    	<!-- ValidationFilter 这个filter负责对请求参数ticket进行验证(ticket参数是负责子系统与CAS进行验证交互的凭证)casServerUrlPrefix:CAS服务访问地址serverName:当前应用所在的主机名 -->
    	<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:8080/</param-value>
    		</init-param>
    	</filter>
    	<filter-mapping>
    		<filter-name>CAS Validation Filter</filter-name>
    		<url-pattern>/*</url-pattern>
    	</filter-mapping>
    
    	<!-- 3.(可选)HttpServletRequestWrapperFilter 这个是HttpServletRequet的包裹类,让他支持getUserPrincipal,getRemoteUser方法来取得用户信息 -->
    	<!-- 该过滤器负责实现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>
    
    	<!-- 4.(可选)AssertionThreadLocalFilter 这个类把Assertion信息放在ThreadLocal变量中,这样应用程序不在web层也能够获取到当前登录信息 Assertion assersion =AssertionHolder.getAssertion(); -->
    	<!--该过滤器使得开发者可以通过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>
    
    </web-app>

     

    四、读取更多的客户端信息

    打开CAS的/WEB-INF/deployerConfigContext.xml,
    找到bean id为attributeRepository的这个配置,修改为如下

    	
    	<bean id="attributeRepository" class="org.jasig.services.persondir.support.jdbc.SingleRowJdbcPersonAttributeDao">
    		<constructor-arg index="0" ref="dataSource" />
    		<constructor-arg index="1">
    			<value>select * from account where {0}</value>
    		</constructor-arg>
    		<!-- 组装sql用的查询条件属性 -->
    		<property name="queryAttributeMapping">
    			<map>
    				<entry key="username" value="email" />
    				<!-- <entry key="username" value="userAccount" /> -->
    			</map>
    		</property>
    		<!-- 如果要组装多个查询条件,需要加上下面这个,默认为AND -->
    		<!-- <property name="queryType">
    			<value>OR</value>
    		</property> -->
    		<!-- 要获取的属性在这里配置 -->
    		<property name="resultAttributeMapping">
    			<map>
    				<!--key为对应的数据库字段名称,value为提供给客户端获取的属性名字,系统会自动填充值 -->
    				<entry key="id" value="id" />
    				<entry key="email" value="email" />
    				<entry key="emailValidated" value="emailValidated" />
    				<entry key="password" value="password" />
    				<entry key="registerTime" value="registerTime" />
    				<entry key="lastLoginTime" value="lastLoginTime" />
    				<entry key="balance" value="balance" />
    			</map>
    		</property>
    	</bean>

    修改该xml文件中最后一个默认的serviceRegistryDao bean,找到<bean class=”org.jasig.cas.services.RegexRegisteredService”>把高亮部分添加进去:

    <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="ignoreAttributes" value="true"/>
                        </bean>

    最后修改WEB-INF\view\jsp\protocol\2.0\casServiceValidationSuccess.jsp文件

    <%@page pageEncoding="UTF-8"%>
    <%@ page session="false" %>
    <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
    <%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
    
    <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="${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>
            <!-- 在server验证成功后,这个页面负责生成与客户端交互的xml信息,在默认的casServiceValidationSuccess.jsp中,只包括用户名,并不提供其他的属性信息,因此需要对页面进行扩展 -->
            <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> 
        </cas:authenticationSuccess>
    
    </cas:serviceResponse>

    然后即可使用以下代码在index.jsp中获取对应的返回对象:

    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    Map<String, Object> attributes = principal.getAttributes();

    以下是我用于测试的index.jsp

    <%@ page language="java" import="java.util.*" contentType="text/html;charset=utf-8"%>
    <%@ page import="org.jasig.cas.client.authentication.AttributePrincipal,org.jasig.cas.client.validation.Assertion,org.jasig.cas.client.util.AbstractCasFilter"%>
    
    <%
    String path = request.getContextPath();
    String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
    %>
    
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
    <html>
    <head>
    	<base href="<%=basePath%>">
    	<title>CAS单点登录VS退出</title>
    </head>
    <body>
    
    <%
    AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
    Map<String, Object> attributes = principal.getAttributes();
    /*for(Map.Entry<String,Object> m: attributes.entrySet()){ 
    	System.out.println(m.getKey()+"---"+m.getValue()); 
    }*/
    %>
    
    [ 单点登录测试 ]<br /><br />
    用户名:<%=principal.getName()%><br />
    id:<%=attributes.get("id")%><br />
    email:<%=attributes.get("email")%><br />
    emailValidated:<%=attributes.get("emailValidated")%><br />
    password:<%=attributes.get("password")%><br />
    registerTime:<%=attributes.get("registerTime")%><br />
    lastLoginTime:<%=attributes.get("lastLoginTime")%><br />
    balance:<%=attributes.get("balance")%><br />
    <br />
    <a href="http://localhost:8080/sway/cas/logout">退出</a><br /><br />
    <hr/>
    <br /><br />
    [ DEBUG ]<br /><br />
    map中元素个数为<%=attributes.size()%>
    
    </body>
    
    </html>

    至此配置完毕,往后再教大家配置对应的SSL加密。

  • 在linux中扩展php中的pdo_mysql模块(编译扩展安装)

    linux版本: centOS 6.4

    php版本: php 5.4.15

    PHP编译安装之后可能需求扩展一些组件比如pdo_mysql,gd什么的,好在php5中有一个phpize工具可以帮助我们轻松的扩展PHP而不需要重新编译PHP。

    首先我们使用命令查看一下已经安装的php扩展模块:
    /usr/local/php/bin/php -m

    进入PHP源码包ext/pdo_mysql目录执行命令:
    ./configure –with-php-config=/usr/local/php/bin/php-config

    然后make和make install

    接着重启您的apache服务器, 再使用命令 /usr/local/php/bin/php -m 即可看到已经添加的对应的pdo_mysql模块了.

  • 取消tomcat自动重载,采用JRebel实时加载进行热部署

    一直都觉得myeclipse+tomcat开发ssh的效率太慢了,主要是因为每次更改后调试都需要重启服务器,就算使用tomcat自身的reloadable,速度野太慢了,跟重启服务器所花的时间差不多,而且修改后session等信息也会丢失,效果跟重启几乎一样。

    经过一番努力的资料搜集,发现了一个很不错的Myeclipse的JRebel插件(也有Eclipse版本的)。

    因为我使用的是 MyEclipse 2013,服务器是 Tomcat 6.0,因此以下教程将以这个版本为例:

    打开 Myeclipse 2013,点击菜单中 Help 的 Install from Site,在打开的窗口中点 Add 按钮, Name处填JRebel,Location处填http://www.zeroturnaround.com/update-site/,然后点ok确定,在下方的列表中选择对应的Eclipse版本然后Next继续:

    2222222222

     

    接着根据提示完成安装。

    安装完成后,对JRebel进行激活,我们点击 Help 中的 JRebel Config Center,在界面中点击Activation,在or paste your license code here下方的文本框中填入对应的激活码即可。

    333333333

    如果你没有激活码,则可以进入https://my.jrebel.com/使用facebook或twiter账号登陆并购买0元的免费Social版本激活码,此激活码能使用一年时间。

    如果激活码有效,则有效果会有蓝色的提示框显示“JRebel Actived”。

    接着在菜单打开windows中的preferences并进入对应的tomcat6.0版本,会看见多了两个关于JRebel settings的选项,我们把这两个选项都勾上,然后在tomcat中的jdk设置中的Optional Java VM arguments填上以下配置信息:

    -Drebel.spring_plugin=true
    -Drebel.aspectj_plugin=true
    -Drebel.struts2_plugin=true
    -noverify
    -Xms512m -Xmx512m -XX:MaxNewSize=512m -XX:MaxPermSize=512m

    其中-Xms512m -Xmx512m -XX:MaxNewSize=512m -XX:MaxPermSize=512m是为了避免jvm的内出不足的情况出现。(JRebel占用内存太大了)

    ok,保存,接下来做最后一步功夫,右击你的Myeclipse项目,在弹出的菜单中选择Add JRebel Nature,然后你会发现你的项目src文件夹中多了一个名为rebel.xml的配置文件(如果你不需要手工设置,则你不需要修改这个文件),知道这里,配置已经成功,此时我们启动tomcat,我们会发现console有对应的JRebel输出,这样就大功告成了。

    好了,享受愉快的编程之旅吧!

    (太懒了,工作中抽时间写这文章,无奈只好忽略细节很多,还望见谅,大家还是多多锻炼一下解决问题的思维吧~~)

  • 解决struts2中首页默认调用index的问题

    在struts 2中,通过在web-xml中配置welcome-file欢迎页面来调用action是无效的。

    以前是直接在index.jsp中加上这个标签 <s:action name=”index” namespace=”/”/>, 但是这样做的话, 对应index的action中result处理就不起作用了。

    经过资料整理后, 最终得出我们可以在struts-xml中的action配置中加入来实现你预期的效果。

    我们可以在默认的package中加上<default-action-ref name=”action名称”/>, 如:

    <package name="default" namespace="/" extends="struts-default">
        <default-action-ref name="index"/>
        <action name="index" class="web.action.IndexAction" method="index">
            <result name="success">index.jsp</result>
        </action>
    </package>

    还有一点不要漏掉,记得清空web.xml中的welcome-file,不然默认是会被调用index.jsp的,对于某些人来说可能会造成错误:

    <welcome-file-list>
        <welcome-file></welcome-file>
    </welcome-file-list>

    这样即可解决这个问题。

  • 解决 IE6 position:fixed 固定定位问题

    就像你所遇到的问题一样, IE6 有太多的 bug 让制作网页的人头疼。这篇文章介绍的是介绍我的如何解决 IE6 不支持 position:fixed; 属性的办法

    ie6-position-fixed

     

    关于 position:fixed; 属性

    生成绝对定位的元素,相对于浏览器窗口进行定位。
    元素的位置通过 “left”, “top”, “right” 以及 “bottom” 属性进行规定。

    position:fixed; 可以让网页上的某个元素固定在一个绝对的位置,即使拉动滚动条位置也不发生变化。(在 LOO2K 博客右下角的那个置顶的小按钮就是用了这个 CSS 属性实现的)

    一般的 position:fixed; 实现方法

    以我的博客为例,在右下角<div id="top">...</div>这个 HTML 元素使用的 CSS 代码如下:

    #top{
        position:fixed;
        bottom:0;
        right:20px;
    }

    实现让<div id="top">...</div>元素固定在浏览器的底部和距离右边的20个像素。

    在 IE6 中实现 position:fixed; 的办法

    刚刚提过,在 IE6 中是不能直接使用 position:fixed; 。你需要一些 CSS Hack 来解决它。(当然,IE6 的问题也不仅仅 position:fixed;)

    相同的还是让 <div id="top">...</div> 元素固定在浏览器的底部和距离右边的20个像素,这次的代码是:

    #top{
        position:fixed;
        _position:absolute;
        bottom:0;
        right:20px;
        _bottom:auto;
        _top:expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight-this.offsetHeight-(parseInt(this.currentStyle.marginTop,10)||0)-(parseInt(this.currentStyle.marginBottom,10)||0)));
    }

    right 跟 left 属性可以用绝对定位的办法解决,而 top 跟 bottom 就需要用上面的表达式来实现。其中在_position:absolute;中的_符号只有 IE6 才能识别,目的是为了区分其他浏览器

    上面的只是一个例子,下面的才是最重要的代码片段:

    使元素固定在浏览器的顶部
    #top{
        _position:absolute;
        _bottom:auto;
        _top:expression(eval(document.documentElement.scrollTop));
    }

    使元素固定在浏览器的底部

    #top{
        _position:absolute;
        _bottom:auto;
        _top:expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight-this.offsetHeight-(parseInt(this.currentStyle.marginTop,10)||0)-(parseInt(this.currentStyle.marginBottom,10)||0)));
    }

    这两段代码只能实现在最底部跟最顶部,你可以使用 _margin-top:10px; 或者 _margin-bottom:10px;修改其中的数值控制元素的位置。

    position:fixed; 闪动问题

    现在,问题还没有完全解决。在用了上面的办法后,你会发现:被固定定位的元素在滚动滚动条的时候会闪动。解决闪动问题的办法是在 CSS 文件中加入:

    *html{
        background-image:url(about:blank);
        background-attachment:fixed;
    }

    其中 * 是给 IE6 识别的。

    到此,IE6 的 position:fixed; 问题已经被解决了。现在 LOO2K 这个博客上的固定定位就是使用的这个办法解决 IE6 固定定位问题的。

     

  • 解决Dreamweaver中文定位问题(光标位置不对/选择代码时对不准/光标偏移)

    最近开始重新学PHP。然后发现Dreamweaver中用鼠标选择代码的时候,光标总是对不准。具体就是,在代码视图中,如果有中文,鼠标点击时,光标的落位总是不准确,总要往前偏位几个字符,即光标偏位了。其实以前也遇到这种情况,一直不知道是怎么回事。

    刚才百度了一下,解决方法如下:

    在首选项中选择字体栏,把Unicode的字体统一设置为宋体/新宋体。问题解决。

    Dreamweaver

    据说可能的原因是DW对中文的支持不好。我们知道,UTF8中,中文应该是占2个字符的。但是这里DW可能把中英文统一作1个字符处理了。导致光标偏移。

  • struts2自定义404错误页面

    最近服务器后台出现一些异常,问题是客户访问一个该网站下不存在的action,为了给客户一个友好的界面提示以及减小服务器端日志文件的内容。就在struts2下进行了如下配置:
    在struts.xml里的package下添加:

    <default-action-ref name="pagenotfound"></default-action-ref>  
    <action name="pagenotfound">  
        <result>/404.jsp</result>  
    </action>

     

    当然struts2只会处理用户访问不存在的action,当用户访问jsp或者html时,是不会处理的。
    这样还要在项目的web.xml下添加:

    <package name="404" extends="struts-default">
    	<default-action-ref name="notFound" />
    	<action name="notFound">
    		<result>/404.jsp</result>
    	</action>
    </package>