Archive for the '技术' Category

Web2.0 , SSO & OpenID

Web2.0的应用越来越多,对SSO的需求也就愈发强烈,Delicious,Flickr,Mail,Blog,43things, Feedburner……,每个应用都有自己的一套Identit需要维护,这带来了很多问题,比如:

每个应用都需要注册一个用户名和密码
每天需要输入很多次同样的认证信息
可能无法注册到自己希望的用户名

如果这些Web2.0应用能够采用某种Single Sign-On系统,会带来很多好处:

简化Web2.0的开发,不需要开发Identity认证,只需要集成SSO的SDK
用户只需要记住一个简单的Identity就可以
统一认证,方便集成各种Web2.0的应用

BTW:这里需要分清Authentication与Authorization的区别:SSO负责的仅仅是Authentication - is proving that You Are Who You Say You Are,Authorization则是某个Identity在这个应用系统中有什么数据,这是Web2.0网站自己的事儿。
最先想到的是Microsoft Passport,它的基本工作原理是:
1) 客户端对Passport合作站点(比如MSN Space)发出访问请求,检查Cookie是否有Passport登陆验证的Cookie,如果没有,则显示"登陆"按钮;
2) 点击登陆按钮,Redirect -> Passport.com 进行验证,参数:

returnUrl - 返回到应用的URL
SiteID - 合作站点的ID

3) Passport检查客户端Cookie,如果用户未登陆(用户有可能在其它的Passport-Enable站点登陆过),则显示登陆页面;如果登陆过,则更新Cookie,到(5);
4) 用户提交登陆数据(用户名、密码,有时还图像验证等),HTTPS发送;
5) Passport验证用户身份,生成sid,重定向回刚才传递的那个returnUrl,也就是Passport的应用站点。
6) Passport合作站点通过预先约定验证SID,并生成本地Cookie,显示"登出"按钮。
其实,类似的SSO方案还有很多,有跨网站应用的,比如Sixapart的Typekey;也有本公司的Passport,比如Sohu Passport(Sohu Passport的认证页面是通过HTTP明文传的…),还有为了其它应用集成的,比如Flickr API中的认证。
这种SSO解决方案中最重要的三个元素为:

SiteID - 标识哪个合作应用站点
ReturnURL - 要返回的页面
SID - 预先约定的某种认证方式。比如对称密钥加密,或者PKI公钥技术

这种解决方案,所有的用户隐私资料都是保存在中心服务器中的。这就带来了一个问题,由谁来替大家Host用户的隐私数据呢?如果是某个中心化的Server,谁能相信这个Server呢?
Livejournal的创始人给出了他的答案 - OpenID。

This is a decentralized identity system, but one that’s actually decentralized and doesn’t […]

Popularity: 69%

Dissect Spam Karma

Spam Karma是一个非常棒的WP插件,用来过滤WP的留言中的Spam。用过WP的朋友或多或少的都受到过Spam疯狂的攻击,SK可以很大程度上的帮助你从这种困境中解脱出来。
Karma [’ka:ma] - 卡马(镍铬丝精密级),是一种度量单位。SK中,用Karma来表示一个留言的"Spam等级",最后根据一个留言的Karma值来判定这个留言是不是Spam。
Update:Ben提醒Karma的另一个意思是佛教中的”因果报应”,也许,这个意思更符合作者的本意。
SK本身是一个WP的插件,而为了有更好的扩展性,SK2也是采用插件的形式来工作的。当然,它的插件工作比起WP的机制来说,简单很多。
Plugin Framework大概有几种模式:
一种如Eclipse那样,采用"微内核+插件"。除了一个微小的核(包括Plugin Framework)之外,其它任何东西都是插件。这就需要尽可能的多留出扩展点,每个插件在做的时候要时刻考虑别人可能从哪个地方来扩展。
一种如Firefox、WordPress这样,主程序相对独立,在独立Standalone程序的基础上,暴露出一些接口,这种扩展性也非常强,当然,这是建立在StandAlone程序暴露出了足够丰富的扩展点的基础上。
这两种都有非常丰富的扩展性,比较适合做大型的Framework,比如Eclipse RCP等等。另外,这两种模式中往往都有"Extension Point"的概念。
另一种方式就简单多了,系统规定好几个Interface,插件只需要实现这几个Interface即可。这样的插件Framework,实现起来比较简单,但是扩展性也非常有限,比较适合做比较专用的小型程序。这种插件的核心概念就是"Interface"。
SK2就是一个这样的例子。
先来看看SK扩展WP的部分:
SK Extend了以下几个Extension:
<?php
add_action(’comment_form’, ’sk2_form_insert’);
add_action(’admin_menu’, ’sk2_add_options’);
add_action(’admin_head’, ’sk2_output_admin_css’);
add_filter(’pre_comment_approved’, ’sk2_fix_approved’);
add_action(’comment_post’, ’sk2_filter_comment’);
 
add_action(’wp_footer’, ’sk2_insert_footer’, 3);
?>
其中,"admin_menu"是用来在菜单中添加一个Option选项,"admin_head"是在Head中添加SK自己的CSS信息,"wp_footer"是在Blog的尾部添加一个SK的Copyright信息。
其余的三个就比较重要了
Extend "comment_form" Extension的是函数"sk2_form_insert",顾名思义,是在Comment Form Load的时候添加代码。
"pre_comment_approved"是一个Trick,防止WP自动发送Comment Notification。
"comment_post"是最重要的一个扩展点,它是在一条Comment被提交之后来调用的,SK的处理也正在此处。
再来看看SK2插件,前面说过它是属于比较简单的第三种形式,看看它的Interface是怎么定义的:
这个类中有三个核心的接口函数分别是
<?php
    function filter_this(&$cmt_object)
    { // override this to do your own filtering
        log_msg (__("Default filter (no action) called for plugin: ", ’sk2′) . $name, 3, $cmt_object->ID);
    }
   
    function treat_this(&$cmt_object)
  […]

Popularity: 34%

First glance at Ruby

大年三十的时候,上班已经没什么事儿了,就仔细读了读以前保存的很多不错的文章,包括这一篇"Ruby, PHP and a Conference",作者是大名鼎鼎的Bruce Eckle,"Thinking in Java"这个经典教材的作者。
一直就很想看看Ruby这个很火的语言,这两天终于有些时间,就找了一些文章看了看。
强烈推荐一篇"10 Things Every Java Programmer Should Know About Ruby",挺不错。
总结一下Ruby吸引我的地方:
1) Case Statement

In Ruby, the case statement can match with any object. It uses the “===” method in Object to perform the match, which can be overridden for your own classes. Since everything is really an object in Ruby, […]

Popularity: 24%

Dissect Lucene - 文件系统

org.apache.lucene.store
Directory, InputStream, OutputStream这三个抽象类构成了一个抽象的文件系统。
Directory中定义了一个基本文件系统的基本操作:
public abstract class Directory {
  /** Returns an array of strings, one for each file in the directory. */
  public abstract String[] list()
       throws IOException;
 
  /** Returns true iff a file with the given name exists. */
  public abstract boolean fileExists(String name)
       throws IOException;
 
  /** Returns the time the named file was last modified. */
  public abstract long fileModified(String name)
       throws IOException;
 
  /** Set the […]

Popularity: 24%

Dissect Lucene - Lucene中的文档

在包org.apache.lucene.document中,三个类,其中DateField是用来处理日期与字符串转换的工具类,来方便的处理日期类型的Field。
Field就像我们学过的数据库中的字段,简单的说,就是一个名值对。这个域有三种属性,分别是

isStored - 是否被存储
isIndexed - 是否被索引
isTokenized - 是否分词

这些属性的组合又构成了四种不同类型的Field,而且各有用途,用Xerdoc DSearch中举个例子:
Keyword(String name, String value)
存储、索引、不分词,用于URI(比如MSN聊天记录的日期域、比如MP3文件的文件全路径等等)
UnIndexed(String name, String value)
存储、不索引、不分词,比如文件的全路径
UnStored(String name, String value)
不存储、索引、分词,比如HTML的正文、Word的内容等等,这部分内容是要被索引的,但是由于具体内容通常很大,没有必要再进行存储,可以到时候根据URI再来挖取。所以,这部分只分词、索引,而不存储。
Text(String name, String value)
存储、索引、分词,比如文件的各种属性,比如MP3文件的歌手、专辑等等。
Text(String name, Reader value)
不存储、索引、分词。
Field经常需要进行Name的比较,比如:
/** Returns a field with the given name if any exist in this document, or
   * null.  If multiple fields exists with this name, this method returns the
   * first value added.
  […]

Popularity: 26%

前两天收到过一条短信:

贵用户取款卡正于《沃尔玛》购物广场刷卡消费8800元,授权确定成功,此笔金额将从你帐户中扣除。如有疑问,请拨:010-5126****卡务部查询。

这样的诈骗越来越多了,如果你打过去,会有人工提示你输入帐户和密码,以此骗取你的银行帐户。
其实,这样的骗局还是很容易被识破的,首先看看发短信的号码:1348462****,正规银行怎么可能用这种号码呢?再看银行的客服电话,中国的各大银行都是5位的特服号:

95533 建设银行
95555 招商银行
95559 交通银行
95566 中国银行
95577 华夏银行
95588 工商银行
95595 光大银行
95599 中国农业银行

如果同样的事情发生在互联网上,有时就没有那么容易区分了。
一次,朋友发给我这个链接,号称免费赠送Q币。仔细看看,就会发现,他的域名是"tencnent"而不是"tencent",这个网页的所有其它链接也都链到了qq.com,粗心的话,很容易就会上当。
这就是常说的钓鱼式攻击

钓鱼式攻击是企图通过官方外观的电子邮件,即時通訊、网站等,冒充真正需要信息的值得信任的人,欺诈性地获取敏感的个人信息(比如口令和信用卡细节)的行为。它是社会工程攻击的一种形式。 - zh.wikipedia.org

记着前段再看IE7的Blog的时候看到过这样一篇文章 - Phishing Filter in IE7,就是IE7中对付这种钓鱼式攻击的方法,很简单:如果你Subscribe了这个服务,那么,每次访问一个URL的时候会首先检查Client端的ok list,如果待访问域名在其中,则直接访问;否则就去Server验证这个URL,当然,还有很多细节问题。
其实,这也是一个需要Participate的Architecture,Server中的Bad URL list需要用户的主动贡献。说来说去,又回到那句话上,It’s An architecture of participation.
Popularity: 27%

Popularity: 27%

JAVA SE 5.0 provides two very useful APIs to help us debug our program, All this two are all class "Thread"’s method:
public StackTraceElement[] getStackTrace()

Returns an array of stack trace elements representing the stack dump of this thread. This method will return a zero-length array if this thread has not started or has terminated. If […]

Popularity: 40%

终于写完,周末就去医院陪奶奶了。先这样吧,最近发生了很多事儿,脑子有点儿乱,也不知道究竟写的怎么样 :(。
最终的文章我放在了这里:
Dissect Eclipse Plugin Framework
希望能对你有些帮助。
Popularity: 26%

Popularity: 26%

Dissect Eclipse Plugin Framework (7)

对于一个良好的插件平台来说,仅有一个良好的插件架构是不够的,还需要有非常方便易用的插件开发环境。Eclipse的PDE就是这样的产品,它能够很大程度帮助程序员开发插件,极大降低其它人“participation”的难度 :-)。
相比之下,Netbeans就没有这样的插件开发环境(Netbeans中,插件斗叫做模块 - "Module"),因此,开发插件还是一件很麻烦的事情,这也就造成了其他人“participation”的困难。
基本上就是这样,Eclipse2.1的插件结构真的非常优秀,看到那些代码的时候更佩服最初设计者的想法。Eclipse2.1 Plugin Framework也有一些缺点,比如不能Load/Unload on the fly(动态加载/卸载),需要重启Eclipse等等。
在Eclipse3.0之后,Eclipse决定遵循OSGi的标准来重构其插件机制,拥抱标准,总是一件美好的事情。
最后强烈推荐 "Contributing to Eclipse",由Erich Gamma、Kent Beck执笔,值得一读。
Popularity: 26%

Popularity: 26%

Dissect Eclipse Plugin Framework (6)

在介绍"Extension Point"之前,先来看一个概念:Eclipse中著名的懒加载原则(Lazy Loading Rule)。

懒加载法则:只有在真正需要的时候才加载插件,实现起来最重要的方面就是声明和实现的分离。

插件的外形(比如名字,ID,图标)等等都在插件描述清单"plugin.xml"中声明,而具体功能封装在class文件中。
这种懒加载原则表现在各个方面,比如最基本的插件启动。系统在启动的时候,只加载和启动最必须的一些插件,而其它插件只有在真正用到的时候才被加载和启动,这样可以最大限度的节省系统启动时的资源和时间。而对用户来说,每次启动也确实有很多插件根本不会去用到。
懒加载还表现在扩展点的应用上,待会儿可以看到具体例子。
接下来就看看"Extension Point",像前面曾经介绍的那样,"Extension Point"是Eclipse Plugin Frame中最核心的概念。首先来看一个Xerdoc DS中"Extension Point"和"Extension"的声明:
<extension-point id="Parser">
    <parameter-def id="class" type="string"/>       
    <parameter-def id="icon" type="string"/>
</extension-point>
这是"core"插件中关于"Parser"的扩展点,你可以定义不同的扩展,来增强Xerdoc DS能够索引文件类型的范围。
<extension plugin-id="com.xerdoc.desktop.core" point-id="Parser" id="MP3FileParser">
    <parameter id="class" value="com.xerdoc.desktop.parser.mp3.MP3FileParser"/>
    <parameter id="icon" value="image/mime_icon_Music_mp3.gif"/>
</extension>
这是"mp3 parser"插件中对此扩展点的一个扩展声明,声明了自己扩展的类和图标。图标完全是为了显示,而其中的"class"则是为了加载真正的功能。
"core"插件会在需要的时候加载所有扩展了这个扩展点的插件:
private static void loadSupportedParsers() {
    … …
   
    try {
        descriptor = manager.getPlugin("com.xerdoc.desktop.core")
                .getDescriptor();
 
        //    得到Parser扩展点声明
        IExtensionPoint extPoint = descriptor.getRegistry()
  […]

Popularity: 27%


Creative Commons License
This work is licensed under a Creative Commons License.

爱情像鲜花,它从不开放,欲望像野草,它疯狂的生长