基本认证过程

在很多场合需要使用基本认证,如果代码仓库的认证授权等,这里先介绍一下基本认证中客户端和服务器的交互过程

  • 浏览器(或者客户端)发起指定路径的访问请求
  • 服务器从客户端发来的头部中寻找Authorization项,如果没有提供,则返回401给浏览器
401 Unauthorized
Server: Apache/2.2.22 (Ubuntu)
WWW-Authenticate: Basic realm="Secure Area"
  • 浏览器(或者客户端)在收到401返回后,会给用户弹出一个认证框,要求用户输入用户名和密码进行认证,在用户输入后,将用户名和密码使用":"隔开并使用base64进行编码,在请求头中加入Authorization项,再次发起请求
Host: code.ideais.net
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.9; rv:27.0) Gecko/20100101 Firefox/27.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-cn,zh;q=0.8,en-us;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Authorization: Basic amlsaWxpOjEyMzQ1Ng==
Connection: keep-alive
Cache-Control: max-age=0
  • 服务器从头中解析出Authorization项的值,使用base64解码得出用户名和密码,然后使用服务器端数据库或者文件中保存的用户名和密码进行比较,如果不一致,再次返回401给浏览器,继续要求输入用户名密码;如果已经通过验证,那么调用正常处理程序。

Base64常用工具

使用python进行base64编解码

>>> import base64
>>> base64.encodestring('jilili:123456')
'amlsaWxpOjEyMzQ1Ng==\n'
>>> base64.decodestring("amlsaWxpOjEyMzQ1Ng==")
'jilili:123456

实现基本认证

很多Web服务器都提供了便利的认证实现,可以直接调用;用户也可以自己编写程序来实现基本认证。

注意:CGI程序在Apache环境中是无法实现基本认证的,应为Apache不提供支持,可以通过用WSGI来包装认证,然后调用CGI来处理。

Apache认证模块基本认证配置

Apache认证模块支持多种认证方式,如:基于文件的,基于MySQL的还有基于LDAP的。这里只以基于MySQL的认证加以说明。

    <LocationMatch /git>
        AuthName "Git"
        AuthType Basic
        #AuthGroupFile /dev/null
        AuthBasicAuthoritative off
        Auth_MySQL on
        Auth_MySQL_Authoritative on
        Auth_MySQL_Host localhost
        Auth_MySQL_DB ideais_net
        Auth_MySQL_Password 123456
        Auth_MySQL_User jilili
        Auth_MySQL_Password_Table "uni_login_account, uni_login_password"
        Auth_MySQL_Password_Clause " and uni_login_account.account_id=uni_login_password.account_id "
        Auth_MySQL_Username_Field account_name
        Auth_MySQL_Password_Field password
        Auth_MySQL_Empty_Passwords off
        Auth_MySQL_Encryption_Types Plaintext Crypt_DES Crypt_MD5 PHP_MD5 MySQL
        require valid-user
    </LocationMatch>

WSGI基本认证实现

WSGI中主要是获取HTTP_AUTHORIZATION,里面的值就是Base64编码过的用户名和密码信息,以下是一些代码片段。

def handle(environ):
    '''
    请求处理
    '''
    is_authorized = False
    http_authorization = environ.get("HTTP_AUTHORIZATION")
    print >> sys.stderr, "HTTP_AUTHORIZATION", http_authorization
    if http_authorization:
        auth_type, auth_body = http_authorization.split(" ", 1)
        if auth_type == "Basic":
            username, password = auth_body.decode("base64").split(":", 1)
            if check_user(username, password):
                is_authorized = True;

    if not is_authorized:
        status = '401 Unauthorized'
        headers = [('Content-type', 'text/html')
               , ('Server', 'Source Server/0.1')
               , ('WWW-Authenticate', 'Basic realm="Secure Area"')] # HTTP Headers
        document = document_401
    else:
        cgi_scripts = "/opt/www/code.ideais.net/cgi/git-http.cgi"
        status, headers, document = wsgi_to_cgi(environ, cgi_scripts, username)

    return status, headers, document

def check_user(username, password):
    '''
    检查用户合法性
    '''
    ...

def application(environ, start_response):
    '''
    应用处理入口
    '''
    environ['wsgi.multithread']  = True
    environ['wsgi.multiprocess'] = True

    environ_strs = ['%s:%s' % (key, value) for key, value in sorted(environ.items())]
    environ_strs = '\n'.join(environ_strs)
    print >> sys.stderr, environ_strs

    status, headers, document = handle(environ)

    start_response(status, headers)

    return document
    ...

[ 编辑 | 历史 ]
最近由“jilili”在“2014-03-18 16:32:16”修改