Using Yan in Ruby Web Application

I will show you the usage of Yan captcha service. In this tutorial, it’s based on a simple ruby web application of the Sinatra web framework.

Before we start to use the service, it is necesary to get Yan running. Download the code from the project page, then build and run it with maven:
mvn jetty:run

To enable the application to use Yan, we have to register our application to get an API Key. If you use Yan 0.3, there is a secret registration page at http://localhost:8080/yan/reg.jsp The page is protected by HTTP Basic Authentication, the username and password are store in ‘realm.properties’ which is considered to locate in the root directory. Open the file you can see the plain text username and password. If you are running the latest development version, there is no long any UI for API Key creation, but restful interface. This won’t be hard to you, pickup your tools such as curl or poster (a firefox extension) to send a HTTP request. Take curl as example, do it like this:
curl -X PUT “http://localhost:8080/yan/apikey/” -d “SinatraTestApp” -u “username:password”

If it works, you will get a line of json:
{“apikey”:”b251b0dc2eed31cac38555b61d4fa6a453923bfd”,”appName”:”SinatraTestApp”}
Save this apikey.

Sinatra is generally considered to be the world’s lightest and smallest web framework. And our application is rather simple. Just check the code:

require "rubygems"
require "sinatra"
require "net/http"
require "yaml"

apikey='b251b0dc2eed31cac38555b61d4fa6a453923bfd'

get '/' do
	conn = Net::HTTP.new('localhost', 8080)
	q = "ip=#{@env['REMOTE_ADDR']}&apikey=#{apikey}&alt=yaml&mode=0"
	resp, data = conn.get("/yan/ticket?#{q}")
	@ticket = YAML::load(data)
	haml :sinatra_captcha
end

post '/' do
	conn = Net::HTTP.new('localhost', 8080)
	q = "ip=#{@env['REMOTE_ADDR']}&apikey=#{apikey}&key=#{params['key']}&code=#{params['captcha']}"
	resp, data = conn.get("/yan/validate?#{q}")
	data
end

use_in_file_templates!
__END__

@@ sinatra_captcha
%html
	%head
		%title Yan Captcha on Sinatra
	%body
		%form{:action=>"/", :method=>"post"}
			%p
				Username:
				%input{:name=>"username", :type=>"text"}
			%p
				Password:
				%input{:name=>"password", :type=>"password"}
			%p
				Captcha:
				%img{:src=>@ticket['url']}
				%br
				%input{:name=>"captcha", :type=>"text"}
				%input{:name=>"key", :type=>"hidden", :value=>@ticket['key']}
				%input{:type=>'submit'}

There are two parts of this application: ruby code and haml. I just use in-file-template for convenience. We define a get handler and a post handler on the path ‘/’. The get handler will request a ticket from Yan which contains captcha image url and ticket key. The post handler will extract user input and submit the Yan’s validator and return user the result. And the HAML code is template for page rendering after GET request.

Maybe you need to install sinatra and some dependency:
sudo gem install sinatra haml

Run the code with a build-in WEBrick
ruby sinatra-yan.rb

Browse to the default url, test it:

For another similar tutorial using python, check Yan’s wiki page:
http://bitbucket.org/sunng/yan/wiki/SampleCode

Thank you for your support. btw, today is my dear girl friend’s birthday, I just wish her happy everyday.

This entry was written by Sunng , posted on Monday December 21 2009at 11:12 pm , filed under 把戏 and tagged , , , . Bookmark the permalink . Post a comment below or leave a trackback: Trackback URL.

10 Responses to “Using Yan in Ruby Web Application”

  • alex says:

    现在captcha技术确实日新月异啊
    这个是搞古文的 http://recaptcha.net
    这个是搞智力测试的 http://server251.theory.cs.cmu.edu/cgi-bin/esp-pix
    然后传统的也五花八门了 http://caca.zoy.org/wiki/PWNtcha
    好像yahoo还是哪还搞语音……

  • alex says:

    不过最实用,也最难破解的,我觉得还是腾讯的中文…… 搞一个行草,再明暗对比一把,不加任何干扰,应该就很难被破解了,笔画太多了,字典也太大了……

    • Sunng says:

      @alex, 中文也有问题,万一没有输入法就完了,验证码是个小东西但是总是卡在最关键的位置,验证码要是出问题了整个系统就彻底不能用了,同样,验证码的accessbility差的话系统也就那啥了。语音是各家都有的。

      • alex says:

        @Sunng, 是啊,所有solution都有context的说。话说我下了你的yan看了下,那个你是不是觉得接口少一些会比较好些,非功能性代码比例有点微高…… 最核心的应该就是一个类似这样的接口吧?
        public interface CaptchaContext {
        String getCaptachaCode();

        void write(final String captchaCode, final OutputStream out,
        final String format, final int width, final int height)
        throws IOException;

        }

        • Sunng says:

          @alex, 我的captchaGenerator因为历史原因做成了stateful的,这个很麻烦,所以要把TicketGenerator和CaptchaGenerator分开。后面可能会慢慢把它们合并起来。
          现在接口是不少,所有的操作都有接口定义了,一个模块里有好几个层次的接口。比如Captcha里,CaptchaService是面向上层的,CaptchaGenerator是面向下层的。
          另外你这个叫Context不太合适吧,还是叫Service比较合适。

          • alex says:

            @Sunng, 我是在gwt里实现一个简单的登录,加上了一个很简单的验证码,暴露出来的servlet叫captchaservice了,然后captchaservice依赖的下层接口就叫captchacontext了……
            话说在gwt里因为客户端也在一块了,用DI不是很方便,然后就用一个final class叫config,服务端、客户端各一个,然后在这个class里定义了各个接口的一个实例,所有其他类都引用config……在单元测试里也可以很方便的修改引用,替换mock等等……这种用法倒是很山寨……

          • Sunng says:

            @alex, 我这是一个验证码service,类似recaptcha,不是提供类库而是提供service。

          • alex says:

            @Sunng, 那确实考虑问题要复杂很多

  • alex says:

    话说你考虑过从与SSO结合的角度来思考captcha的体系吗?比如和SAML之类兼容之类……

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

*
To prove you're a person (not a spam script), type the security word shown in the picture. Click on the picture to hear an audio file of the word.
Click to hear an audio file of the anti-spam word