标签存档: Django

使用Google Captcha作网站的验证码(Python)

CAPTCHA 是Completely Automated Public Turing test to tell Computers and Humans Apart的缩写,够长吧!中文意思是:"全自动区分电脑与人类的图灵测试" 简单来说就是用于区分人类和电脑的验证码图片.

感谢伟大的Google提供了其实现和相应的API. 相关文档大家可自行参考:

http://www.google.com/recaptcha

最近公司的一个项目要使用验证码防止恶意脚本批量注册或遍历破解密码. 传统的解决方式很多,比如IP记录,验证码…但最常见的还是验证码功能,但现在验证码也是有很多弱点的,很容易被破解. 敢兴趣的朋友可以参看相关文章(http://www.xklog.org/article/internet/python-verify-code-recognize-discuz.html) 其实最主要想使用Google Captacha的原因是想省力气,懒得写太复杂的算法.  囧~呵呵

Google Captacha有相应的python实现,但是我感觉默认库可定制性太差,所以只部分采用.

开始之前我先来说下Google Captacha的原理.

传统的验证码是网站先随即生成一个字符,然后保存字符串到session或数据库中.然后把这个字符串生成图片,输出到页面上去.

Google Captacha构架如下图:

 

步骤看上去比较多,其实对网站开发者来说重点是3步.即图上的1、3、4. 下面稍微解释下

第一步是用户从Google服务器上得到一个验证码图片

没错,是用户获取。对开发人员来说就是在页面加一个ajax调用,当用户加载页面的同时,加载一个Google Capatcha图片即可.

第二步是当用户把含验证码信息表单提到后台,也是web应用最常见的步骤.

第三步是网站后台把用户得到的验证码传递给Google Capatcha服务器验证用户输入的是否正确.

这里就是重点所在,Google服务器如何知道当前验证码输入是否和第一步用户请求到的图片一致,就需要一样东西,即一个随机码. 此外要确定是哪一个网站用户申请的图片和哪一个网站验证图片,需要另外一样东西,即私钥/公钥.

上面简单介绍了下原理,对开发人员来说读代码比看文章管用的多.下面直接开始

一、注册网站私/公钥.https://www.google.com/recaptcha/admin/create

Public Key:

6LcmCL8S*****JH2rJ5l9mgj9xIq63wM0Qeliafm

Private Key:

6LcmCL8S******DFxZh7GY-nWdklo9zWJpQ9Y0yY4

二、编写用户页面,公钥是用户向Google服务器请求一个Capatcha图片. 此步骤需要用户公钥

由于国内加载GoogleCapatcha图片比较慢,我用了异步请求.大致代码如下

HTML


				

分享一个Python数字分页工具

有点造轮子的嫌疑,感觉Django自带的分页工具不是很好用,部分重写了下

Python代码

class Pagination():
				'''
				Pagination tools
				'''
				count = 0
				page_size = 10
				current_page = 1
				page_gap = 5
				page_count = 0

				def __init__(self,object_list,page_size,current_page = 1,page_gap=5):
				u'''Simple Pagination tools
				object_list: The queue or list objects
				page_size:    Page size
				current_page: Current Page
				page_gap:    The gap of current page, inlcude left gap and right gap. the same value is this.
				'''
				self.object_list = object_list
				self.count = self._get_count()
				self.page_size = page_size
				self.current_page = current_page
				self.page_gap = page_gap
				if not self.count % page_size:
				self.page_count = self.count / page_size
				else:
				self.page_count = self.count / page_size + 1

				def _get_count(self):
				"Returns the total number of objects, across all pages."
				try:
				self.count = self.object_list.count()
				except (AttributeError, TypeError):
				self.count = len(self.object_list)
				return self.count

				def page_objects(self):
				bottom = (self.current_page-1)*self.page_size
				top = bottom + self.page_size
				if top >= self.count:
				top = self.count
				return self.object_list[bottom:top]

				def has_pre(self):
				if self.current_page > 1:
				return True
				return False

				def has_next(self):
				if self.current_page < self.page_count:
				return True
				return False

				def has_first(self):
				if self.current_page == 1:
				return False
				return True

				def has_last(self):
				if self.current_page == self.page_count:
				return False
				return True

				def page_limit(self):
				return self.page_size * (self.current_page - 1)

				def page_left_list(self):
				if self.current_page > self.page_gap:
				return range(self.page_count+1)[self.current_page-self.page_gap:self.current_page]
				return range(self.page_count+1)[1:self.current_page]

				def page_right_list(self):
				if self.current_page + self.page_gap <= self.page_count:
				return range(self.page_count+1)[self.current_page+1:self.current_page+self.page_gap+1]
				return range(self.page_count+1)[self.current_page+1:]

				def page_list(self):
				return range(self.page_count+1)[1:]

				def page_html_format(self):
				html = '<div id="pagination">'
				if self.has_first():
				html += '<a href="?page=1">First</a>n'
				html += ''.join(['<a href="?page=%s">%s</a>n'%(n,n) for n in self.page_left_list()])
				html += '<a class="a1">%s</a>n'%self.current_page
				html += ''.join(['<a href="?page=%s">%s</a>n'%(n,n) for n in self.page_right_list()])
				if self.has_last():
				html += '<a href="?page=%s">Last</a>n'%self.page_count
				html += '</div>'
				return html

使用方法很简单

...
				PAGE_SIZE=10
				try:
				pagination = Pagination(results,PAGE_SIZE,current_page=int(request.GET.get('page', 1)),page_gap=10)
				except InvalidPage:
				raise Http404

				context = {
				'query': sTerm,
				'object_list': pagination.page_objects(),
				'pagination': pagination,
				}
				return render_to_response('search/search.html',RequestContext(request,context))
				...

模板使用

{{ pagination.page_html_format }}

效果如下(自己定义CSS)

django邮件发送(支持模板)

项目里一个模块,重新封装了python的smtplib和django的template

主要功能:

  1. 支持多用户接受

  2. 支持模板

  3. 良好的处理了中文问题

代码如下:


				#!/usr/bin/env python

				# -*- coding: UTF-8 -*-

				#

				#

				__author__="Fred"

				__date__ ="$2010-5-31 17:15:35$"

				import smtplib, base64

				from django.template import loader, Context

				CHARSET = 'utf-8'

				FROM_ADD = 'xxxxxx@163.com'

				SMTP_SERVER = 'smtp.163.com'

				SMTP_USER = 'xxxxx'

				SMTP_PASS = 'xxxxx'

				class SendMail:

				u'''

				邮件发送模块,此模块运行使用django模块来发送邮件

				参数介绍(*必填):

				subject *邮件主题

				template *邮件模板位置

				context *邮件模板上下文

				to_addr *目的地址,允许发给多人,格式为['test@examp.com','test2@example',......]

				smtp_server 发件服务器地址

				smtp_server_port 发件服务器端口号

				from_addr 发信地址

				from_addr_name 发信人名称

				user 发件箱登录用户名

				pass 发件箱登录密码

				e.g:

				from ureg.helper import SendMail

				mail = SendMail('test','email/register.html',{'tmp_code':'123'},['ad@fengsage.cn'])

				mail.send_mail()

				u'''

				def __init__(self,subject,template,context,to_addr,smtp_server=SMTP_SERVER, smtp_server_port = 25 ,from_addr=FROM_ADD,from_addr_name=u'Mytut视频网',user=SMTP_USER, passwd=SMTP_PASS):

				self.subject = subject

				self.template = template

				self.context = context

				self.to_addr  = to_addr

				self.from_addr = from_addr

				self.from_addr_name = from_addr_name

				self.username = user

				self.password = passwd

				self.smtp_server_port = smtp_server_port

				self.mailserver = smtp_server

				def send_mail(self):

				from email.mime.text import MIMEText

				from email.mime.multipart import MIMEMultipart

				from email import Utils

				msgRoot = MIMEMultipart('related')

				msgRoot['Subject'] = self.subject

				msgRoot['From'] =  self.named(self.from_addr, self.from_addr_name)

				if len(self.to_addr) == 1:

				msgRoot['To'] = self.to_addr[0]

				else:

				msgRoot['To'] = Utils.COMMASPACE.join(self.to_addr)

				pass

				msgRoot['Date'] = Utils.formatdate()

				# Encapsulate the plain and HTML versions of the message body in an

				# 'alternative' part, so message agents can decide which they want to display.

				msgAlternative = MIMEMultipart('alternative')

				msgRoot.attach(msgAlternative)

				#根据模板生成html

				html = self.render(self.template, self.context).encode('utf-8')

				msgText = MIMEText(html,'html',_charset='utf-8')

				msgAlternative.attach(msgText)

				smtp = smtplib.SMTP(self.mailserver,self.smtp_server_port)

				smtp.login(self.username, self.password)

				result = smtp.sendmail(self.from_addr, self.to_addr, msgRoot.as_string())

				smtp.quit()

				def render(self,template,context):

				u'''

				读取模板内容,并赋值

				u'''

				if template:

				t = loader.get_template(template)

				return t.render(Context(context))

				return context

				def named(self,mail,name):

				u'''

				格式化右键发信/收信格式

				e.g fredzhu <me@fengsage.cn>

				u'''

				if name:

				return '%s <%s>' % (name,mail)

				return mail

				

使用方法:


				mail = SendMail(USER_REGISTER,'email/register.html',{'tmp_code':tmp_code,'tmp_user':username},[email])

				mail.send_mail()

 

django blog 系统

这段时间复习了django的一些知识。拿来做个blog练练手~

SVN:http://fengproject.googlecode.com/svn/trunk/fenghome/

功能比较简单,但是包含了django框架的方方面面。

功能:

1、基本的文章管理。采用django的admin管理系统,这也是django一大特色。

2、评论。发布文章时,可控制的允许是否评论,以及对评论管理。

3、模板系统。可以自定义模板,可在setting.py里设置。当然目前就做一套模板。

4、国际化。全站所有字符串都采用国际化设置,目前只做了英汉2种。

前前后后断断续续做了7个晚上。这对于django的快速开发来说效率不算高,还算是低下!