The Django Book

Chapter 12: Sessions, Users, and Registration

绗崄浜岀珷 浼氳瘽銆佺敤鎴峰拰娉ㄥ唽

Its time for a confession: weve been deliberately ignoring an incredibly important aspect of Web development prior to this point. So far, weve thought of the traffic visiting our sites as some faceless, anonymous mass hurtling itself against our carefully designed pages.

鏄椂鍊欐壙璁や簡锛氭垜浠湁鎰忕殑閬垮紑浜唚eb寮鍙戜腑鏋佸叾閲嶈鐨勬柟闈€傚埌鐩墠涓烘锛屾垜浠兘鍦ㄥ亣瀹氾紝缃戠珯娴侀噺鏄ぇ閲忕殑鍖垮悕鐢ㄦ埛甯︽潵鐨勩

This isnt true, of course. The browsers hitting our sites have real humans behind them (some of the time, at least). Thats a big thing to ignore: the Internet is at its best when it serves to connect people , not machines. If were going to develop truly compelling sites, eventually were going to have to deal with the bodies behind the browsers.

杩欏綋鐒朵笉瀵癸紝娴忚鍣ㄧ殑鑳屽悗閮芥槸娲荤敓鐢熺殑浜(鑷冲皯鏌愪簺鏃跺欐槸)銆傛垜浠拷鐣ヤ簡涓浠堕噸瑕佺殑浜嬫儏锛氫簰鑱旂綉鏈嶅姟浜庝汉鑰屼笉鏄満鍣ㄣ傝寮鍙戜竴涓湡姝d护浜哄績鍔ㄧ殑缃戠珯锛屾垜浠繀椤婚潰瀵规祻瑙堝櫒鍚庨潰娲荤敓鐢熺殑浜恒

Unfortunately, its not all that easy. HTTP is designed to be stateless that is, each and every request happens in a vacuum. Theres no persistence between one request and the next, and we cant count on any aspects of a request (IP address, user agent, etc.) to consistently indicate successive requests from the same person.

寰堜笉骞革紝杩欏苟涓嶅鏄撱侶TTP琚璁′负”鏃犵姸鎬”锛屾瘡娆¤姹傞兘澶勪簬鐩稿悓鐨勭┖闂翠腑銆傚湪涓娆¤姹傚拰涓嬩竴娆¤姹備箣闂存病鏈変换浣曠姸鎬佷繚鎸侊紝鎴戜滑鏃犳硶鏍规嵁璇锋眰鐨勪换浣曟柟闈(IP鍦板潃锛岀敤鎴蜂唬鐞嗙瓑)鏉ヨ瘑鍒潵鑷悓涓浜虹殑杩炵画璇锋眰銆

In this chapter youll learn how to handle this lack of state. Well start at the lowest level (cookies ), and work up to the high-level tools for handling sessions, users and registration.

鍦ㄦ湰绔犱腑浣犲皢瀛︿細濡備綍鎼炲畾鐘舵佺殑闂銆傚ソ浜嗭紝鎴戜滑浼氫粠杈冧綆鐨勫眰娆(cookies)寮濮嬶紝鐒跺悗杩囨浮鍒扮敤楂樺眰鐨勫伐鍏锋潵鎼炲畾浼氳瘽锛岀敤鎴峰拰娉ㄥ唽鐨勯棶棰樸

Cookies

Cookies

Browser developers long ago recognized that HTTPs statelessness poses a huge problem for Web developers, and thus cookies were born. A cookie is a small piece of information that browsers store on behalf of Web servers. Every time a browser requests a page from a certain server, it gives back the cookie that it initially received.

娴忚鍣ㄧ殑寮鍙戣呭湪寰堟棭鐨勬椂鍊欏氨宸茬粡鎰忚瘑鍒帮紝 HTTP’s 鐨勬棤鐘舵佷細瀵筗eb寮鍙戣呭甫鏉ュ緢澶х殑闂锛屼簬鏄(cookies)搴旇繍鑰岀敓銆俢ookies 鏄祻瑙堝櫒涓 Web 鏈嶅姟鍣ㄥ瓨鍌ㄧ殑涓灏忔淇℃伅銆傛瘡娆℃祻瑙堝櫒浠庢煇涓湇鍔″櫒璇锋眰椤甸潰鏃讹紝瀹冨悜鏈嶅姟鍣ㄥ洖閫佷箣鍓嶆敹鍒扮殑cookies

Lets take a look how this might work. When you open your browser and type in google.com , your browser sends an HTTP request to Google that starts something like this:

鏉ョ湅鐪嬪畠鏄庝箞宸ヤ綔鐨勩傚綋浣犳墦寮娴忚鍣ㄥ苟璁块棶 google.com 锛屼綘鐨勬祻瑙堝櫒浼氱粰Google鍙戦佷竴涓狧TTP璇锋眰锛岃捣濮嬮儴鍒嗗氨璞¤繖鏍凤細

GET / HTTP/1.1
Host: google.com
...

When Google replies, the HTTP response looks something like the following:

褰 Google鍝嶅簲鏃讹紝HTTP鐨勫搷搴旀槸杩欐牱鐨勶細

HTTP/1.1 200 OK
Content-Type: text/html
Set-Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671;
            expires=Sun, 17-Jan-2038 19:14:07 GMT;
            path=/; domain=.google.com
Server: GWS/2.1
...

Notice the Set-Cookie header. Your browser will store that cookie value (PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671 ) and serve it back to Google every time you access the site. So the next time you access Google, your browser is going to send a request like this:

娉ㄦ剰 Set-Cookie 鐨勫ご閮ㄣ備綘鐨勬祻瑙堝櫒浼氬瓨鍌╟ookie鍊( PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671 ) 锛岃屼笖姣忔璁块棶google 绔欑偣閮戒細鍥為佽繖涓猚ookie鍊笺傚洜姝ゅ綋浣犱笅娆¤闂瓽oogle鏃讹紝浣犵殑娴忚鍣ㄤ細鍙戦佸儚杩欐牱鐨勮姹傦細

GET / HTTP/1.1
Host: google.com
Cookie: PREF=ID=5b14f22bdaf1e81c:TM=1167000671:LM=1167000671
...

Google then can use that Cookie value to know that youre the same person who accessed the site earlier. This value might, for example, be a key into a database that stores user information. Google could (and does) use it to display your name on the page.

浜庢槸 Cookies 鐨勫间細鍛婅瘔Google锛屼綘灏辨槸鏃╀簺鏃跺欒闂繃Google缃戠珯鐨勪汉銆傝繖涓煎彲鑳芥槸鏁版嵁搴撲腑瀛樺偍鐢ㄦ埛淇℃伅鐨刱ey锛屽彲浠ョ敤瀹冨湪椤甸潰涓婃樉绀轰綘鐨勭敤鎴峰悕銆

Getting and Setting Cookies

瀛樺彇Cookies

When dealing with persistence in Django, most of the time youll want to use the higher-level session and/or user frameworks discussed a little later in this chapter. However, well pause and look at how to read and write cookies at a low level. This should help you understand how the rest of the tools discussed in the chapter actually work, and it will come in handy if you ever need to play with cookies directly.

鍦―jango涓鐞嗘寔涔呭寲锛屽ぇ閮ㄥ垎鏃跺欎綘浼氭洿鎰挎剰鐢ㄩ珮灞備簺鐨剆ession 鍜/鎴 鍚庨潰瑕佽璁虹殑user 妗嗘灦銆備絾鍦ㄦ涔嬪墠锛屾垜浠渶瑕佸仠涓嬫潵鍦ㄥ簳灞傜湅鐪嬪浣曡鍐檆ookies銆傝繖浼氬府鍔╀綘鐞嗚В鏈珷鑺傚悗闈㈣璁ㄨ鐨勫伐鍏锋槸濡備綍宸ヤ綔鐨勶紝鑰屼笖濡傛灉浣犻渶瑕佽嚜宸辨搷浣渃ookies锛岃繖涔熶細鏈夋墍甯姪銆

Reading cookies that are already set is incredibly simple. Every request object has a COOKIES object that acts like a dictionary; you can use it to read any cookies that the browser has sent to the view:

璇诲彇宸茬粡璁剧疆濂界殑cookies鏋佸叾绠鍗曪紝姣忎釜request瀵硅薄閮芥湁涓涓 COOKIES 瀵硅薄锛屽彲浠ヨ薄浣跨敤瀛楀吀鑸娇鐢ㄥ畠锛屼綘鍙互璇诲彇浠讳綍娴忚鍣ㄥ彂缁欒鍥(view)鐨勪换浣昪ookies:

def show_color(request):
    if "favorite_color" in request.COOKIES:
        return HttpResponse("Your favorite color is %s" % \
            request.COOKIES["favorite_color"])
    else:
        return HttpResponse("You don't have a favorite color.")

Writing cookies is slightly more complicated. You need to use the set_cookie() method on an HttpResponse object. Heres an example that sets the favorite_color cookie based on a GET parameter:

鍐檆ookies绋嶅井澶嶆潅鐐癸紝闇瑕佺敤 HttpResponse 瀵硅薄鐨 set_cookie() 鏂规硶鏉ュ啓銆傝繖鍎挎湁涓熀浜 GET 鍙傛暟鏉ヨ缃 favorite_color cookie鐨勪緥瀛愶細

def set_color(request):
    if "favorite_color" in request.GET:

        # Create an HttpResponse object...
        response = HttpResponse("Your favorite color is now %s" % \
            request.GET["favorite_color"])

        # ... and set a cookie on the response
        response.set_cookie("favorite_color",
                            request.GET["favorite_color"])

        return response

    else:
        return HttpResponse("You didn't give a favorite color.")

You can also pass a number of optional arguments to response.set_cookie() that control aspects of the cookie, as shown in Table 12-1.

浣犲彲浠ョ粰 response.set_cookie() 浼犻掍竴浜涘彲閫夌殑鍙傛暟鏉ユ帶鍒禼ookie鐨勮涓猴紝璇﹁琛12-1銆

Table 12-1: Cookie options
Parameter Default Description
max_age None Age (in seconds) that the cookie should last. If this parameter is None , the cookie will last only until the browser is closed.
expires None The actual date/time when the cookie should expire. It needs to be in the format "Wdy, DD-Mth-YY HH:MM:SS GMT" . If given, this parameter overrides the max_age parameter.
path "/"

The path prefix that this cookie is valid for. Browsers will only pass the cookie back to pages below this path prefix, so you can use this to prevent cookies from being sent to other sections of your site.

This is especially useful when you dont control the top level of your sites domain.

domain None

The domain that this cookie is valid for. You can use this parameter to set a cross-domain cookie. For example, domain=".example.com" will set a cookie that is readable by the domains www.example.com , www2.example.com , and an.other.sub.domain.example.com .

If this parameter is set to None , a cookie will only be readable by the domain that set it.

secure False If set to True , this parameter instructs the browser to only return this cookie to pages accessed over HTTPS.
琛 12-1: Cookie 閫夐」
鍙傛暟 缂虹渷鍊 鎻忚堪
max_age None cookies鐨勬寔缁湁鏁堟椂闂达紙浠ョ璁★級锛屽鏋滆缃负 None cookies 鍦ㄦ祻瑙堝櫒鍏抽棴鐨勬椂鍊欏氨澶辨晥浜嗐
expires None cookies鐨勮繃鏈熸椂闂达紝鏍煎紡锛 "Wdy, DD-Mth-YY HH:MM:SS GMT" 濡傛灉璁剧疆杩欎釜鍙傛暟锛屽畠灏嗚鐩 max_age 鍙傛暟銆
path "/"

cookie鐢熸晥鐨勮矾寰勫墠缂锛屾祻瑙堝櫒鍙細鎶奵ookie鍥炰紶缁欏甫鏈夎璺緞鐨勯〉 闈紝杩欐牱浣犲彲浠ラ伩鍏嶅皢cookie浼犵粰绔欑偣涓殑鍏朵粬鐨勫簲鐢ㄣ

褰撲綘鐨勫簲鐢ㄤ笉澶勪簬绔欑偣椤跺眰鐨勬椂鍊欙紝杩欎釜鍙傛暟浼氶潪甯告湁鐢ㄣ

domain None

cookie鐢熸晥鐨勭珯鐐广備綘鍙敤杩欎釜鍙傛暟鏉ユ瀯閫犱竴涓法绔檆ookie銆傚锛 domain=".example.com" 鎵鏋勯犵殑cookie瀵逛笅闈㈣繖浜涚珯鐐归兘鏄彲 璇荤殑锛 www.example.comwww2.example.coman.other.sub.domain.example.com

濡傛灉璇ュ弬鏁拌缃负 None 锛宑ookie鍙兘鐢辫缃畠鐨勭珯鐐硅鍙栥

secure False 濡傛灉璁剧疆涓 True 锛屾祻瑙堝櫒灏嗛氳繃HTTPS鏉ュ洖浼燾ookie銆

The Mixed Blessing of Cookies

濂藉潖鍙傚崐鐨凜ookies

You might notice a number of potential problems with the way cookies work. Lets look at some of the more important ones:

涔熻浣犲凡缁忔敞鎰忓埌浜嗭紝cookies鐨勫伐浣滄柟寮忓彲鑳藉鑷寸殑闂锛屼竴璧锋潵鐪嬬湅鍏朵腑涓浜涢噸瑕佺殑鏂归潰锛

Storage of cookies is essentially voluntary; browsers dont guarantee anything. In fact, all browsers enable users to control the policy for accepting cookies. If you want to see just how vital cookies are to the Web, try turning on your browsers prompt to accept every cookie option.

cookies瀛樺彇瀹屽叏鏄潪寮哄埗鎬х殑锛屾祻瑙堝櫒涓嶄繚璇佽繖涓鐐广備簨瀹炰笂锛屾墍鏈夌殑娴忚鍣ㄩ兘璁╃敤鎴疯嚜宸辨帶鍒 鏄惁鎺ュ彈cookies銆傚鏋滀綘鎯崇煡閬揷ookies瀵逛簬web搴旂敤鏈夊閲嶈锛屼綘鍙互璇曠潃鎵撳紑杩欎釜娴忚鍣ㄧ殑 閫夐」锛氭彁绀烘垜鎺ュ彈姣忔cookie銆

Despite their nearly universal use, cookies are still the definition of unreliability. This means that developers should check that a user actually accepts cookies before relying on them.

灏界cookies骞夸负浣跨敤锛屼絾浠嶈璁や负鏄笉鍙潬鐨勭殑銆傝繖鎰忓懗鐫锛屽紑鍙戣呬娇鐢╟ookies涔嬪墠蹇呴』 妫鏌ョ敤鎴锋槸鍚﹀彲浠ユ帴鏀禼ookie銆

More important, you should never store important data in cookies. The Web is filled with horror stories of developers whove stored unrecoverable information in browser cookies only to have that data purged by the browser for one reason or another.

鏇撮噸瑕佺殑鏄紝*姘歌繙* 涔熶笉瑕佸湪cookie涓瓨鍌ㄩ噸瑕佺殑鏁版嵁銆傚紑鍙戣呭湪cookie涓瓨鍌ㄤ簡涓嶅彲鎭㈠ 鐨勬暟鎹紝鑰屾祻瑙堝櫒鍗村洜涓烘煇绉嶅師鍥犲皢cookie涓殑鏁版嵁娓呭緱涓骞蹭簩鍑锛岃繖鏍蜂护浜哄彂鎸囩殑鏁呬簨鍦 Web涓栫晫涓瘮姣旂殕鏄

Cookies (especially those not sent over HTTPS) are not secure. Because HTTP data is sent in cleartext, cookies are extremely vulnerable to snooping attacks. That is, an attacker snooping on the wire can intercept a cookie and read it. This means you should never store sensitive information in a cookie.

Cookie(鐗瑰埆鏄偅浜涙病閫氳繃HTTPS浼犺緭鐨)鏄潪甯镐笉瀹夊叏鐨勩傚洜涓篐TTP鏁版嵁鏄互鏄庢枃鍙戦佺殑锛屾墍浠 鐗瑰埆瀹规槗鍙楀埌鍡呮帰鏀诲嚮銆備篃灏辨槸璇达紝鍡呮帰鏀诲嚮鑰呭彲浠ュ湪缃戠粶涓嫤鎴苟璇诲彇cookies锛屽洜姝や綘瑕 缁濆閬垮厤鍦╟ookies涓瓨鍌ㄦ晱鎰熶俊鎭

Theres an even more insidious attack, known as a man-in-the-middle attack, wherein an attacker intercepts a cookie and uses it to pose as another user. Chapter 19 discusses attacks of this nature in depth, as well as ways to prevent it.

杩樻湁涓绉嶈绉颁负”涓棿浜”鐨勬敾鍑绘洿闃撮櫓锛屾敾鍑昏呮嫤鎴竴涓猚ookie骞跺皢鍏剁敤浜庡彟涓涓敤鎴枫 绗19绔犲皢娣卞叆璁ㄨ杩欑鏀诲嚮鐨勬湰璐ㄤ互鍙婂浣曢伩鍏嶃

Cookies arent even secure from their intended recipients. Most browsers provide easy ways to edit the content of individual cookies, and resourceful users can always use tools like mechanize ( http://wwwsearch.sourceforge.net/mechanize/ ) to construct HTTP requests by hand.

鍗充娇浠庨鎯充腑鐨勬帴鏀惰呰繑鍥炵殑cookie涔熸槸涓嶅畨鍏ㄧ殑锛屽洜涓哄ぇ澶氭暟娴忚鍣ㄩ兘鎻愪緵浜嗗緢鏂逛究鐨勬柟娉曟潵 淇敼cookies鐨勫唴瀹癸紝鏈夋妧鏈儗鏅殑鐢ㄦ埛鐢氳嚦鍙互鐢ㄥ儚mechanize ( http://wwwsearch.sourceforge.net/mechanize/ ) 杩欐牱鐨勫伐鍏锋潵鎵嬪伐鏋勯燞TTP璇锋眰銆

So you cant store data in cookies that might be sensitive to tampering. The canonical mistake in this scenario is storing something like IsLoggedIn=1 in a cookie when a user logs in. Youd be amazed at the number of sites that make mistakes of this nature; it takes only a second to fool these sites security systems.

鍥犳涓嶈兘鍦╟ookies涓瓨鍌ㄥ彲鑳戒細琚鏀圭殑鏁忔劅鏁版嵁锛屸滅粡鍏糕濋敊璇槸锛氬湪cookies涓瓨鍌 IsLoggedIn=1 锛屼互鏍囪瘑鐢ㄦ埛宸茬粡鐧诲綍銆傜姱杩欑被閿欒鐨勭珯鐐规暟閲忓鐨勪护浜洪毦浠ョ疆淇★紱 缁曡繃杩欎簺缃戠珯鐨勫畨鍏ㄧ郴缁熶篃鏄槗濡傚弽鎺屻

Djangos Session Framework

Django鐨 Session 妗嗘灦

With all of these limitations and potential security holes, its obvious that cookies and persistent sessions are examples of those pain points in Web development. Of course, Djangos goal is to be an effective painkiller, so it comes with a session framework designed to smooth over these difficulties for you.

鐢变簬瀛樺湪鐨勯檺鍒朵笌瀹夊叏婕忔礊锛宑ookies鍜屾寔缁т細璇濆凡缁忔垚涓篧eb寮鍙戜腑浠や汉澶寸柤鐨勫吀鑼冦傚ソ娑堟伅鏄紝Django鐨勭洰鏍囨鏄珮鏁堢殑鈥滃ご鐤兼潃鎵嬧濓紝瀹冭嚜甯︾殑session妗嗘灦浼氬府浣犳悶瀹氳繖浜涢棶棰樸

This session framework lets you store and retrieve arbitrary data on a per-site visitor basis. It stores data on the server side and abstracts the sending and receiving of cookies. Cookies use only a hashed session IDnot the data itselfthus protecting you from most of the common cookie problems.

浣犲彲浠ョ敤session 妗嗘灦鏉ュ瓨鍙栨瘡涓闂呬换鎰忔暟鎹紝杩欎簺鏁版嵁鍦ㄦ湇鍔″櫒绔瓨鍌紝骞剁敤閫氳繃cookie鏉ヤ紶杈撴暟鎹憳瑕併俢ookies鍙瓨鍌ㄦ暟鎹殑鍝堝笇浼氳瘽ID锛岃屼笉鏄暟鎹湰韬紝浠庤岄伩鍏嶄簡澶ч儴鍒嗙殑甯歌cookie闂銆

Lets look at how to enable sessions and use them in views.

涓嬮潰鎴戜滑鏉ョ湅鐪嬪浣曟墦寮session鍔熻兘锛屽苟鍦ㄨ鍥句腑浣跨敤瀹冦

Enabling Sessions

鎵撳紑 Sessions鍔熻兘

Sessions are implemented via a piece of middleware (see Chapter 15) and a Django model. To enable sessions, youll need to follow these steps:

Sessions 鍔熻兘鏄氳繃涓涓腑闂翠欢(middleware)鍜屼竴涓ā鍨(model)鏉ュ疄鐜扮殑銆傝鎵撳紑sessions鍔熻兘锛岄渶瑕佷互涓嬪嚑姝ユ搷浣滐細

  1. Edit your MIDDLEWARE_CLASSES setting and make sure MIDDLEWARE_CLASSES contains 'django.contrib.sessions.middleware.SessionMiddleware' .

  1. 缂栬緫 MIDDLEWARE_CLASSES 閰嶇疆锛岀‘淇 MIDDLEWARE_CLASSES 涓寘鍚 'django.contrib.sessions.middleware.SessionMiddleware'

  1. Make sure 'django.contrib.sessions' is in your INSTALLED_APPS setting (and run manage.py syncdb if you have to add it).

  1. 纭 INSTALLED_APPS 涓湁 'django.contrib.sessions' (濡傛灉浣犳槸鍒氭墦寮杩欎釜搴旂敤锛屽埆蹇樹簡杩愯 manage.py syncdb )

The default skeleton settings created by startproject have both of these bits already installed, so unless youve removed them, you probably dont have to change anything to get sessions to work.

濡傛灉椤圭洰鏄敤 startproject 鏉ュ垱寤虹殑锛岄厤缃枃浠朵腑閮藉凡缁忓畨瑁呬簡杩欎簺涓滆タ锛岄櫎闈炰綘鑷繁鍒犻櫎锛屾甯告儏鍐典笅锛屼綘鏃犻渶浠讳綍璁剧疆灏卞彲浠ヤ娇鐢╯ession鍔熻兘銆

If you dont want to use sessions, you might want to remove the SessionMiddleware line from MIDDLEWARE_CLASSES and 'django.contrib.sessions' from your INSTALLED_APPS . It will save you only a small amount of overhead, but every little bit counts.

濡傛灉涓嶉渶瑕乻ession鍔熻兘锛屼綘鍙互鍒犻櫎 MIDDLEWARE_CLASSES 璁剧疆涓殑 SessionMiddlewareINSTALLED_APPS 璁剧疆涓殑 'django.contrib.sessions' 銆傝櫧鐒惰繖鍙細鑺傜渷寰堝皯鐨勫紑閿锛屼絾绉皯鎴愬鍟娿

Using Sessions in Views

鍦ㄨ鍥句腑浣跨敤Session

When SessionMiddleware is activated, each HttpRequest objectthe first argument to any Django view functionwill have a session attribute, which is a dictionary-like object. You can read it and write to it in the same way youd use a normal dictionary. For example, in a view you could do stuff like this:

SessionMiddleware 婵娲诲悗锛屾瘡涓紶缁欒鍥(view)鍑芥暟鐨勭涓涓弬鏁癭`HttpRequest`` 瀵硅薄閮芥湁涓涓 session 灞炴э紝杩欐槸涓涓瓧鍏稿瀷鐨勫璞°備綘鍙互璞$敤鏅氬瓧鍏镐竴鏍锋潵鐢ㄥ畠銆備緥濡傦紝鍦ㄨ鍥(view)涓綘鍙互杩欐牱鐢細

# Set a session value:
request.session["fav_color"] = "blue"

# Get a session value -- this could be called in a different view,
# or many requests later (or both):
fav_color = request.session["fav_color"]

# Clear an item from the session:
del request.session["fav_color"]

# Check if the session has a given key:
if "fav_color" in request.session:
    ...

You can also use other mapping methods like keys() and items() on request.session .

鍏朵粬鐨勬槧灏勬柟娉曪紝濡 keys()items()request.session 鍚屾牱鏈夋晥锛

There are a couple of simple rules for using Djangos sessions effectively:

涓嬮潰鏄竴浜涙湁鏁堜娇鐢―jango sessions鐨勭畝鍗曡鍒欙細

  • Use normal Python strings as dictionary keys on request.session (as opposed to integers, objects, etc.). This is more of a convention than a hard-and-fast rule, but its worth following.

  • 鐢ㄦ甯哥殑瀛楃涓蹭綔涓簁ey鏉ヨ闂瓧鍏 request.session 锛 鑰屼笉鏄暣鏁般佸璞℃垨鍏跺畠浠涔堢殑銆 杩欎笉鏄粈涔堝己纭殑鏉¤锛屼絾鍊煎緱閬靛惊銆

  • Session dictionary keys that begin with an underscore are reserved for internal use by Django. In practice, the framework uses only a small number of underscore-prefixed session variables, but unless you know what they all are (and you are willing to keep up with any changes in Django itself), staying away from underscore prefixes will keep Django from interfering with your application.

  • Session瀛楀吀涓互涓嬪垝绾垮紑澶寸殑key鍊兼槸Django鍐呴儴淇濈暀key鍊笺傛鏋跺彧浼氱敤寰堝皯鐨勫嚑涓笅鍒掔嚎 寮澶寸殑session鍙橀噺锛岄櫎闈炰綘鐭ラ亾浠栦滑鐨勫叿浣撳惈涔夛紝鑰屼笖鎰挎剰璺熶笂Django鐨勫彉鍖栵紝鍚﹀垯锛屾渶濂 涓嶈鐢ㄨ繖浜涗笅鍒掔嚎寮澶寸殑鍙橀噺锛屽畠浠細璁〥jango鎼呬贡浣犵殑搴旂敤銆

  • Dont replace request.session with a new object, and dont access or set its attributes. Use it like a Python dictionary.

  • 涓嶈鐢ㄤ竴涓柊瀵硅薄鏉ユ浛鎹㈡帀 request.session 锛屼篃涓嶈瀛樺彇鍏跺睘鎬э紝璞$敤鏅歅ython瀛楀吀涓鏍风敤瀹冦

Lets take a look at a few quick examples. This simplistic view sets a has_commented variable to True after a user posts a comment. Its a simple (but not particularly secure) way of preventing a user from posting more than one comment:

鎴戜滑鏉ョ湅涓畝鍗曠殑渚嬪瓙銆傝繖鏄釜绠鍗曞埌涓嶈兘鍐嶇畝鍗曠殑渚嬪瓙锛氬湪鐢ㄦ埛鍙戜簡涓娆¤瘎璁哄悗灏 has_commented 璁剧疆涓 True 锛岃繖鏄釜绠鍗曪紙浣嗕笉寰堝畨鍏級鐨勩侀槻姝㈢敤鎴峰娆¤瘎璁虹殑鏂规硶銆

def post_comment(request, new_comment):
    if request.session.get('has_commented', False):
        return HttpResponse("You've already commented.")
    c = comments.Comment(comment=new_comment)
    c.save()
    request.session['has_commented'] = True
    return HttpResponse('Thanks for your comment!')

This simplistic view logs in a member of the site:

涓嬮潰鏄竴涓緢绠鍗曠殑绔欑偣鐧诲綍瑙嗗浘(view)锛

def login(request):
    try:
        m = Member.objects.get(username__exact=request.POST['username'])
        if m.password == request.POST['password']:
            request.session['member_id'] = m.id
            return HttpResponse("You're logged in.")
    except Member.DoesNotExist:
        return HttpResponse("Your username and password didn't match.")

And this one logs out a member, according to login() :

杩欐槸閫鍑虹櫥褰曪紝鏍规嵁 login() :

def logout(request):
    try:
        del request.session['member_id']
    except KeyError:
        pass
    return HttpResponse("You're logged out.")

Note

娉ㄦ剰

In practice, this is a lousy way of logging users in. The authentication framework discussed shortly handles this task for you in a much more robust and useful manner. These examples are deliberately simplistic so that you can easily see whats going on.

鍦ㄥ疄璺典腑锛岃繖鏄緢鐑傜殑鐢ㄦ埛鐧诲綍鏂瑰紡锛岀◢鍚庤璁虹殑璁よ瘉(authentication )妗嗘灦浼氬府浣犱互鏇村仴澹拰鏈夊埄鐨勬柟寮忔潵澶勭悊杩欎簺闂銆傝繖浜涢潪甯哥畝鍗曠殑渚嬪瓙鍙槸鎯宠浣犵煡閬撹繖涓鍒囨槸濡備綍宸ヤ綔鐨勩

Setting Test Cookies

璁剧疆娴嬭瘯Cookies

As just mentioned, you cant rely on every browser accepting cookies. So, as a convenience, Django provides an easy way to test whether a users browser accepts cookies. You just need to call request.session.set_test_cookie() in a view, and check request.session.test_cookie_worked() in a subsequent viewnot in the same view call.

灏卞儚鍓嶉潰鎻愬埌鐨勶紝浣犱笉鑳芥寚鏈涙墍鏈夌殑娴忚鍣ㄩ兘鍙互鎺ュ彈cookie锛屽洜姝わ紝Django涓轰簡鏂逛究锛屼篃鎻愪緵浜嗘鏌ョ敤鎴锋祻瑙堝櫒鏄惁鎺ュ彈cookie鐨勭畝鍗曟柟娉曘備綘鍙渶鍦ㄨ鍥(view)涓皟鐢 request.session.set_test_cookie() 锛屽苟鍦ㄥ悗缁殑瑙嗗浘(view)銆佽屼笉鏄綋鍓嶇殑瑙嗗浘(view)涓鏌 request.session.test_cookie_worked()

This awkward split between set_test_cookie() and test_cookie_worked() is necessary due to the way cookies work. When you set a cookie, you cant actually tell whether a browser accepted it until the browsers next request.

铏界劧鎶 set_test_cookie()test_cookie_worked() 鍒嗗紑鐨勫仛娉曠湅璧锋潵鏈変簺绗ㄦ嫏锛屼絾鐢变簬cookie鐨勫伐浣滄柟寮忥紝杩欐棤鍙伩鍏嶃傚綋璁剧疆涓涓猚ookie鏃跺欙紝鍙兘绛夋祻瑙堝櫒涓嬫璁块棶鐨勬椂鍊欙紝浣犳墠鑳界煡閬撴祻瑙堝櫒鏄惁鎺ュ彈cookie銆

Its good practice to use delete_test_cookie() to clean up after yourself. Do this after youve verified that the test cookie worked.

妫鏌ookie鏄惁鍙互姝e父宸ヤ綔鍚庯紝浣犲緱鑷繁鐢 delete_test_cookie() 鏉ユ竻闄ゅ畠锛岃繖鏄釜濂戒範鎯

Heres a typical usage example:

杩欐槸涓吀鍨嬩緥瀛愶細

def login(request):

    # If we submitted the form...
    if request.method == 'POST':

        # Check that the test cookie worked (we set it below):
        if request.session.test_cookie_worked():

            # The test cookie worked, so delete it.
            request.session.delete_test_cookie()

            # In practice, we'd need some logic to check username/password
            # here, but since this is an example...
            return HttpResponse("You're logged in.")

        # The test cookie failed, so display an error message. If this
        # was a real site we'd want to display a friendlier message.
        else:
            return HttpResponse("Please enable cookies and try again.")

    # If we didn't post, send the test cookie along with the login form.
    request.session.set_test_cookie()
    return render_to_response('foo/login_form.html')

Note

娉ㄦ剰

Again, the built-in authentication functions handle this check for you.

鍐嶆寮鸿皟锛屽唴缃殑璁よ瘉鍑芥暟浼氬府浣犲仛妫鏌ョ殑銆

Using Sessions Outside of Views

鍦ㄨ鍥(View)澶栦娇鐢⊿ession

Internally, each session is just a normal Django model defined in django.contrib.sessions.models . Each session is identified by a more-or-less random 32-character hash stored in a cookie. Because its a normal model, you can access sessions using the normal Django database API:

浠庡唴閮ㄦ潵鐪嬶紝姣忎釜session閮藉彧鏄竴涓櫘閫氱殑Django model锛堝湪 django.contrib.sessions.models 涓畾涔)銆傛瘡涓猻ession閮界敱涓涓殢鏈虹殑32瀛楄妭鍝堝笇涓叉潵鏍囪瘑锛屽苟瀛樺偍浜庢暟鎹簱涓傜敱浜庤繖鏄竴涓櫘閫氱殑model锛屼綘鍙互鐢ㄤ竴鑸殑Django 鏁版嵁搴揂PI鏉ヨ鍙杝ession銆

>>> from django.contrib.sessions.models import Session
>>> s = Session.objects.get(pk='2b1189a188b44ad18c35e113ac6ceead')
>>> s.expire_date
datetime.datetime(2005, 8, 20, 13, 35, 12)

Youll need to call get_decoded() to get the actual session data. This is necessary because the dictionary is stored in an encoded format:

浣犲緱鐢 get_decoded() 鏉ヨ鍙栧疄闄呯殑session鏁版嵁锛屽洜涓簊ession瀛楀吀缁忚繃浜嗙紪鐮佸瓨鍌ㄣ

>>> s.session_data
'KGRwMQpTJ19hdXRoX3VzZXJfaWQnCnAyCkkxCnMuMTExY2ZjODI2Yj...'
>>> s.get_decoded()
{'user_id': 42}

When Sessions Are Saved

浣曟椂淇濆瓨Session

By default, Django only saves to the database if the session has been modified that is, if any of its dictionary values have been assigned or deleted:

缂虹渷鐨勬儏鍐典笅锛孌jango鍙細鍦╯ession鍙戠敓鍙樺寲鐨勬椂鍊欐墠浼氬瓨鍏ユ暟鎹簱锛屾瘮濡傝锛屽瓧鍏歌祴鍊兼垨鍒犻櫎銆

# Session is modified.
request.session['foo'] = 'bar'

# Session is modified.
del request.session['foo']

# Session is modified.
request.session['foo'] = {}

# Gotcha: Session is NOT modified, because this alters
# request.session['foo'] instead of request.session.
request.session['foo']['bar'] = 'baz'

To change this default behavior, set SESSION_SAVE_EVERY_REQUEST to True . If SESSION_SAVE_EVERY_REQUEST is True , Django will save the session to the database on every single request, even if it wasnt changed.

浣犲彲浠ヨ缃 SESSION_SAVE_EVERY_REQUESTTrue 鏉ユ敼鍙樿繖涓缂虹渷琛屼负銆傚鏋 SESSION_SAVE_EVERY_REQUEST 璁剧疆涓 True 锛孌jango 浼氬湪姣忔璇锋眰鐨勬椂鍊欓兘鎶妔ession瀛樺埌鏁版嵁搴撲腑锛屽嵆浣挎病鏈変换浣曟敼鍙樸

Note that the session cookie is sent only when a session has been created or modified. If SESSION_SAVE_EVERY_REQUEST is True , the session cookie will be sent on every request. Similarly, the expires part of a session cookie is updated each time the session cookie is sent.

娉ㄦ剰锛屼細璇漜ookie鍙細鍦ㄥ垱寤哄拰淇敼鐨勬椂鍊欐墠浼氶佸嚭銆備絾濡傛灉 SESSION_SAVE_EVERY_REQUEST 璁剧疆涓 True 锛屼細璇漜ookie浼氬湪姣忔璇锋眰鐨勬椂鍊欓兘浼氶佸嚭銆傚悓鏃讹紝姣忔浼氳瘽cookie閫佸嚭鐨勬椂鍊欙紝鍏 expires 鍙傛暟閮戒細鏇存柊銆

Browser-Length Sessions vs. Persistent Sessions

娴忚鍣ㄥ叧闂嵆澶辨晥浼氳瘽 vs. 鎸佷箙浼氳瘽

You might have noticed that the cookie Google sent us contained expires=Sun, 17-Jan-2038 19:14:07 GMT; . Cookies can optionally contain an expiration date that advises the browser on when to remove the cookie. If a cookie doesnt contain an expiration value, the browser will expire it when the user closes his or her browser window. You can control the session frameworks behavior in this regard with the SESSION_EXPIRE_AT_BROWSER_CLOSE setting.

浣犲彲鑳芥敞鎰忓埌浜嗭紝Google缁欐垜浠彂閫佺殑cookie涓湁 expires=Sun, 17-Jan-2038 19:14:07 GMT; cookie鍙互鏈夎繃鏈熸椂闂达紝杩欐牱娴忚鍣ㄥ氨鐭ラ亾浠涔堟椂鍊欏彲浠ュ垹闄ookie浜嗐傚鏋渃ookie娌℃湁璁剧疆杩囨湡鏃堕棿锛屽綋鐢ㄦ埛鍏抽棴娴忚鍣ㄧ殑鏃跺欙紝cookie灏辫嚜鍔ㄨ繃鏈熶簡銆備綘鍙互鏀瑰彉 SESSION_EXPIRE_AT_BROWSER_CLOSE 鐨勮缃潵鎺у埗session妗嗘灦鐨勮繖涓琛屼负銆

By default, SESSION_EXPIRE_AT_BROWSER_CLOSE is set to False , which means session cookies will be stored in users browsers for SESSION_COOKIE_AGE seconds (which defaults to two weeks, or 1,209,600 seconds). Use this if you dont want people to have to log in every time they open a browser.

缂虹渷鎯呭喌涓嬶紝 SESSION_EXPIRE_AT_BROWSER_CLOSE 璁剧疆涓 False 锛岃繖鏍凤紝浼氳瘽cookie鍙互鍦ㄧ敤鎴锋祻瑙堝櫒涓繚鎸佹湁鏁堣揪 SESSION_COOKIE_AGE 绉掞紙缂虹渷璁剧疆鏄袱鍛紝鍗1,209,600 绉掞級銆傚鏋滀綘涓嶆兂鐢ㄦ埛姣忔鎵撳紑娴忚鍣ㄩ兘蹇呴』閲嶆柊鐧婚檰鐨勮瘽锛岀敤杩欎釜鍙傛暟鏉ュ府浣犮

If SESSION_EXPIRE_AT_BROWSER_CLOSE is set to True , Django will use browser-length cookies.

濡傛灉 SESSION_EXPIRE_AT_BROWSER_CLOSE 璁剧疆涓 True 锛屽綋娴忚鍣ㄥ叧闂椂锛孌jango浼氫娇cookie澶辨晥銆

Other Session Settings

鍏朵粬鐨凷ession璁剧疆

Besides the settings already mentioned, a few other settings influence how Djangos session framework uses cookies, as shown in Table 12-2.

闄や簡涓婇潰鎻愬埌鐨勮缃紝杩樻湁涓浜涘叾浠栫殑璁剧疆鍙互褰卞搷Django session妗嗘灦濡備綍浣跨敤cookie锛岃瑙佽〃 12-2.

Table 12-2. Settings that influence cookiebehavior
Setting Description Default
SESSION_COOKIE_DOMAIN The domain to use for session cookies. Set this to a string such as ".lawrence.com" for cross-domain cookies, or use None for a standard cookie. None
SESSION_COOKIE_NAME The name of the cookie to use for sessions. This can be any string. "sessionid"
SESSION_COOKIE_SECURE Whether to use a secure cookie for the session cookie. If this is set to True , the cookie will be marked as secure, which means that browsers will ensure that the cookie is only sent via HTTPS. False
琛 12-2. 褰卞搷cookie琛屼负鐨勮缃
璁剧疆 鎻忚堪 缂虹渷鍊
SESSION_COOKIE_DOMAIN session cookie鐢熸晥鐨勭珯鐐癸紝璺ㄧ珯鐐圭敓鏁堢殑 cookie鍙互杩欐牱璁剧疆锛歚`”.lawrence.com”`` None 涓烘爣鍑哻ookie None
SESSION_COOKIE_NAME 鐢ㄤ簬session 鐨刢ookie鍚嶇О锛屽彲浠ユ槸浠讳綍 瀛楃涓 "sessionid"
SESSION_COOKIE_SECURE 鏄惁鍦╯ession涓娇鐢ㄥ畨鍏╟ookie锛屽鏋滆缃 True , cookie灏变細鏍囪涓哄畨鍏紝 杩欐剰鍛崇潃cookie鍙細閫氳繃HTTPS鏉ヤ紶杈 False

Technical Details

鎶鏈粏鑺

For the curious, here are a few technical notes about the inner workings of the session framework:

濡傛灉浣犺繕鏄ソ濂囩殑璇濓紝涓嬮潰鏄竴浜涘叧浜巗ession妗嗘灦鍐呴儴宸ヤ綔鏂瑰紡鐨勬妧鏈粏鑺傦細

The session dictionary accepts any Python object capable of being pickled. See the documentation for Pythons built-in pickle module for information about how this works.

session 瀛楀吀鍜屾櫘閫歅ython瀵硅薄涓鏍凤紝鏀寔搴忓垪鍖栵紝璇﹁Python鏂囨。涓唴缃 pickle 妯″潡鐨勯儴鍒嗐

Session data is stored in a database table named django_session .

Session 鏁版嵁瀛樺湪鏁版嵁搴撹〃 django_session

Session data is fetched upon demand. If you never access request.session , Django wont hit that database table.

Session 鏁版嵁鍦ㄩ渶瑕佺殑鏃跺欐墠浼氳鍙栵紝濡傛灉浣犱粠涓嶄娇鐢 request.session 锛 Django涓嶄細鍔ㄧ浉鍏虫暟鎹簱琛ㄧ殑涓鏍规瘺銆

Django only sends a cookie if it needs to. If you dont set any session data, it wont send a session cookie (unless SESSION_SAVE_EVERY_REQUEST is set to True ).

Django 鍙湪闇瑕佺殑鏃跺欐墠閫佸嚭cookie銆傚鏋滀綘鍘嬫牴鍎垮氨娌℃湁璁剧疆浠讳綍浼氳瘽鏁版嵁锛屽畠涓嶄細 閫佸嚭浼氳瘽cookie(闄ら潪 SESSION_SAVE_EVERY_REQUEST 璁剧疆涓 True )

The Django sessions framework is entirely, and solely, cookie based. It does not fall back to putting session IDs in URLs as a last resort, as some other tools (PHP, JSP) do.

Django session 妗嗘灦瀹屽叏鑰屼笖鍙兘鍩轰簬cookie锛屼笉浼氬悗閫鍒版妸浼氳瘽ID缂栫爜鍦║RL涓傦紙鍍忔煇浜涘伐鍏(PHP,JSP)閭f牱锛

This is an intentional design decision. Putting sessions in URLs dont just make URLs ugly, but also make your site vulnerable to a certain form of session ID theft via the Referer header.

杩欐槸涓涓湁鎰忚屼负涔嬬殑璁捐锛屾妸session鏀惧湪URL涓笉鍙槸闅剧湅锛屾洿閲嶈鐨勬槸杩欒浣犵殑绔欑偣 寰堝鏄撳彈鍒版敾鍑烩斺旈氳繃 Referer header杩涜session ID”绐冨惉”鑰屽疄鏂界殑鏀诲嚮銆

If youre still curious, the source is pretty straightforward; look in django.contrib.sessions for more details.

濡傛灉浣犺繕鏄ソ濂囷紝闃呰婧愪唬鐮佹槸鏈鐩存帴鍔炴硶锛岃瑙 django.contrib.sessions

Users and Authentication

鐢ㄦ埛涓嶢uthentication

Were now halfway to linking browsers directly to Real People. Sessions give us a way of persisting data through multiple browser requests; the second part of the equation is using those sessions for user login. Of course, we cant just trust that users are who they say they are, so we need to authenticate them along the way.

鐜板湪锛屾垜浠氳繃娴忚鍣ㄨ繛鎺ョ湡瀹炵敤鎴风殑鐩爣宸茬粡瀹屾垚涓鍗婁簡銆傞氳繃session锛屾垜浠彲浠ュ湪澶氭娴忚鍣ㄨ姹備腑淇濇寔鏁版嵁锛 鎺ヤ笅鏉ョ殑閮ㄥ垎灏辨槸鐢╯ession鏉ュ鐞嗙敤鎴风櫥褰曚簡銆傚綋鐒讹紝涓嶈兘浠呭嚟鐢ㄦ埛鐨勪竴闈箣璇嶏紝鎴戜滑灏辩浉淇★紝鎵浠ユ垜浠渶瑕佽璇併

Naturally, Django provides tools to handle this common task (and many others). Djangos user authentication system handles user accounts, groups, permissions, and cookie-based user sessions. This system is often referred to as an auth/auth (authentication and authorization) system. That name recognizes that dealing with users is often a two-step process. We need to

褰撶劧浜嗭紝Django 涔熸彁渚涗簡宸ュ叿鏉ュ鐞嗚繖鏍风殑甯歌浠诲姟锛堝氨鍍忓叾浠栧父瑙佷换鍔′竴鏍凤級銆侱jango 鐢ㄦ埛璁よ瘉绯荤粺澶勭悊鐢ㄦ埛甯愬彿锛岀粍锛屾潈闄愪互鍙婂熀浜巆ookie鐨勭敤鎴蜂細璇濄傝繖涓郴缁熶竴鑸绉颁负 auth/auth (璁よ瘉涓庢巿鏉)绯荤粺锛岃繖涓郴缁熺殑鍚嶇О鍚屾椂涔熻〃鏄庝簡鐢ㄦ埛甯歌鐨勪袱姝ュ鐞嗐傛垜浠渶瑕

  1. Verify (authenticate ) that a user is who he or she claims to be (usually by checking a username and password against a database of users)

  1. 楠岃瘉 (璁よ瘉) 鐢ㄦ埛鏄惁鏄粬鎵瀹gО鐨勭敤鎴(涓鑸氳繃鏌ヨ鏁版嵁搴撻獙璇佸叾鐢ㄦ埛鍚嶅拰瀵嗙爜)

  1. Verify that the user is authorized to perform some given operation (usually by checking against a table of permissions)

  1. 楠岃瘉鐢ㄦ埛鏄惁鎷ユ湁鎵ц鏌愮鎿嶄綔鐨 鎺堟潈 (閫氬父浼氶氳繃妫鏌ヤ竴涓潈闄愯〃鏉ョ‘璁)

Following these needs, Djangos auth/auth system consists of a number of parts:

鏍规嵁杩欎簺闇姹傦紝Django 璁よ瘉/鎺堟潈 绯荤粺浼氬寘鍚互涓嬬殑閮ㄥ垎锛

  • Users : People registered with your site

  • 鐢ㄦ埛 : 鍦ㄧ綉绔欐敞鍐岀殑浜

  • Permissions : Binary (yes/no) flags designating whether a user may perform a certain task

  • 鏉冮檺 : 鐢ㄤ簬鏍囪瘑鐢ㄦ埛鏄惁鎷ユ湁鏌愮鎿嶄綔鐨勪簩杩涘埗(yes/no)鏍囧織

  • Groups : A generic way of applying labels and permissions to more than one user

  • :涓绉嶅彲浠ュ皢鏍囪鍜屾潈闄愬簲鐢ㄤ簬澶氫釜鐢ㄦ埛鐨勫父鐢ㄦ柟娉

  • Messages : A simple way to queue and display system messages to users

  • Messages : 鍚戠敤鎴锋樉绀洪槦鍒楀紡鐨勭郴缁熸秷鎭殑甯哥敤鏂规硶

  • Profiles : A mechanism to extend the user object with custom fields

  • Profiles : 閫氳繃鑷畾涔夊瓧娈垫墿灞曠敤鎴峰璞$殑鏈哄埗

If youve used the admin tool (detailed in Chapter 6), youve already seen many of these tools, and if youve edited users or groups in the admin tool, youve actually been editing data in the auth systems database tables.

濡傛灉浣犲凡缁忕敤浜哸dmin宸ュ叿(璇﹁绗6绔)锛屽氨浼氱湅瑙佽繖浜涘伐鍏风殑澶ч儴鍒嗐傚鏋滃凡缁忕敤浜哸dmin宸ュ叿鏉ョ紪杈戠敤鎴峰拰缁勶紝浣犲疄闄呬笂灏卞凡缁忓湪缂栬緫璁よ瘉绯荤粺涓暟鎹簱琛ㄣ

Enabling Authentication Support

鎵撳紑璁よ瘉鏀寔

Like the session tools, authentication support is bundled as a Django application in django.contrib , which needs to be installed. Like the session system, its also installed by default, but if youve removed it, youll need to follow these steps to install it:

鍍弒ession宸ュ叿涓鏍凤紝璁よ瘉鏀寔涔熸槸涓涓狣jango搴旂敤锛屾斁鍦 django.contrib 涓紝鎵浠ヤ篃闇瑕佸畨瑁呫備笌session绯荤粺鐩镐技锛屽畠涔熸槸缂虹渷瀹夎鐨勶紝浣嗗鏋滃畠宸茬粡琚垹闄や簡锛岄氳繃浠ヤ笅姝ラ涔熻兘閲嶆柊瀹夎涓婏細

  1. Make sure the session framework is installed as described earlier in this chapter. Keeping track of users obviously requires cookies, and thus builds on the session framework.

  1. 鏍规嵁鏈珷鏃╁墠鐨勯儴鍒嗙‘璁ゅ凡缁忓畨瑁呬簡session 妗嗘灦锛岄渶瑕佺‘璁ょ敤鎴蜂娇鐢╟ookie锛岃繖鏍穝esson 妗嗘灦鎵嶈兘姝e父浣跨敤銆

  1. Put 'django.contrib.auth' in your INSTALLED_APPS setting and run manage.py syncdb .

  1. 'django.contrib.auth' 鏀惧湪浣犵殑 INSTALLED_APPS 璁剧疆涓紝鐒跺悗杩愯 manage.py syncdb

  1. Make sure that 'django.contrib.auth.middleware.AuthenticationMiddleware' is in your MIDDLEWARE_CLASSES setting*after* SessionMiddleware .

  1. 纭 SessionMiddleware 鍚庨潰鐨 MIDDLEWARE_CLASSES 璁剧疆涓寘鍚 'django.contrib.auth.middleware.AuthenticationMiddleware'

With that installation out of the way, were ready to deal with users in view functions. The main interface youll use to access users within a view is request.user ; this is an object that represents the currently logged-in user. If the user isnt logged in, this will instead be an AnonymousUser object (see below for more details).

杩欐牱瀹夎鍚庯紝鎴戜滑灏卞彲浠ュ湪瑙嗗浘(view)鐨勫嚱鏁颁腑鐢ㄥ鐞唘ser浜嗐傚湪瑙嗗浘涓瓨鍙杣sers锛屼富瑕佺敤 request.user 锛涜繖涓璞¤〃绀哄綋鍓嶅凡鐧诲綍鐨勭敤鎴凤紝濡傛灉鐢ㄦ埛杩樻病鐧诲綍锛岃繖灏辨槸涓涓 鍖垮悕 瀵硅薄(缁嗚妭瑙佷笅)

You can easily tell if a user is logged in with the is_authenticated() method:

浣犲彲浠ュ緢瀹规槗鐨勯氳繃 is_authenticated() 鏂规硶鏉ュ垽鏂竴涓敤鎴锋槸鍚﹀凡缁忕櫥褰曚簡

if request.user.is_authenticated():
    # Do something for authenticated users.
else:
    # Do something for anonymous users.

Using Users

浣跨敤User瀵硅薄

Once you have a User often from request.user , but possibly through one of the other methods discussed shortlyyou have a number of fields and methods available on that object. AnonymousUser objects emulate some of this interface, but not all of it, so you should always check user.is_authenticated() before assuming youre dealing with a bona fide user object. Tables 12-3 and 12-4 list the fields and methods, respectively, on User objects.

User 瀹炰緥涓鑸粠 request.user 锛屾垨鏄叾浠栦笅闈㈠嵆灏嗚璁ㄨ鍒扮殑鏂规硶鍙栧緱锛屽畠鏈夊緢澶氬睘鎬у拰鏂规硶銆 AnonymousUser 瀵硅薄妯℃嫙浜 閮ㄥ垎 鐨勬帴鍙o紝浣嗕笉鏄叏閮紝鍦ㄦ妸瀹冨綋鎴愮湡姝g殑user瀵硅薄 浣跨敤鍓嶏紝浣犲緱妫鏌ヤ竴涓 user.is_authenticated()

Table 12-3. Fields on User Objects
Field Description
username Required; 30 characters or fewer. Alphanumeric characters only (letters, digits, and underscores).
first_name Optional; 30 characters or fewer.
last_name Optional; 30 characters or fewer.
email Optional. Email address.
password Required. A hash of, and metadata about, the password (Django doesnt store the raw password). See the Passwords section for more about this value.
is_staff Boolean. Designates whether this user can access the admin site.
is_active Boolean. Designates whether this account can be used to log in. Set this flag to False instead of deleting accounts.
is_superuser Boolean. Designates that this user has all permissions without explicitly assigning them.
last_login A datetime of the users last login. This is set to the current date/time by default.
date_joined A datetime designating when the account was created. This is set to the current date/time by default when the account is created.
琛 12-3. User 瀵硅薄灞炴
灞炴 鎻忚堪
username 蹇呭~; 灏戜簬绛変簬30瀛楃. 鍙厑璁稿瓧绗︼紝鏁板瓧锛屼笅鍒掔嚎
first_name 鍙; 灏戜簬绛変簬30瀛楃.
last_name 鍙; 灏戜簬绛変簬30瀛楃.
email 鍙. 閭欢鍦板潃.
password 蹇呭~. 瀵嗙爜鐨勬憳瑕乭ash(Django涓嶄細瀛樺偍鍘熷瀵嗙爜)锛岃瑙佸瘑鐮佺珷鑺傞儴鍒
is_staff 甯冨皵鍊. 鐢ㄦ埛鏄惁鎷ユ湁缃戠珯鐨勭鐞嗘潈闄.
is_active 甯冨皵鍊. 鏄惁鍏佽鐢ㄦ埛鐧诲綍, 璁剧疆涓篳`False``锛屽彲浠ヤ笉鐢ㄥ垹闄ょ敤鎴锋潵绂佹 鐢ㄦ埛鐧诲綍
is_superuser 甯冨皵鍊. 鐢ㄦ埛鏄惁鎷ユ湁鎵鏈夋潈闄愶紝鑰屾棤闇浠讳綍鏄惧紡鐨勬潈闄愬垎閰嶅畾涔
last_login 鐢ㄦ埛鏈鍚庣櫥褰曠殑鏃堕棿锛岀己鐪佷細璁剧疆涓哄綋鍓嶆椂闂
date_joined 鍒涘缓鐢ㄦ埛鐨勬椂闂达紝褰撶敤鎴峰垱寤烘椂锛岀己鐪佺殑璁剧疆涓哄綋鍓嶇殑鏃堕棿
Table 12-4. Methods on User Objects
Method Description
is_authenticated() Always returns True for real User objects. This is a way to tell if the user has been authenticated. This does not imply any permissions, and it doesnt check if the user is active. It only indicates that the user has sucessfully authenticated.
is_anonymous() Returns True only for AnonymousUser objects (and False for real User objects). Generally, you should prefer using is_authenticated() to this method.
get_full_name() Returns the first_name plus the last_name , with a space in between.
set_password(passwd) Sets the users password to the given raw string, taking care of the password hashing. This doesnt actually save the User object.
check_password(passwd) Returns True if the given raw string is the correct password for the user. This takes care of the password hashing in making the comparison.
get_group_permissions() Returns a list of permission strings that the user has through the groups he or she belongs to.
get_all_permissions() Returns a list of permission strings that the user has, both through group and user permissions.
has_perm(perm) Returns True if the user has the specified permission, where perm is in the format "package.codename" . If the user is inactive, this method will always return False .
has_perms(perm_list) Returns True if the user has all of the specified permissions. If the user is inactive, this method will always return False .
has_module_perms(app_label) Returns True if the user has any permissions in the given app_label . If the user is inactive, this method will always return False .
get_and_delete_messages() Returns a list of Message objects in the users queue and deletes the messages from the queue.
email_user(subj, msg) Sends an email to the user. This email is sent from the DEFAULT_FROM_EMAIL setting. You can also pass a third argument, from_email , to override the From address on the email.
get_profile() Returns a site-specific profile for this user. See the Profiles section for more on this method.
琛 12-4. User 瀵硅薄鏂规硶
鏂规硶 鎻忚堪
is_authenticated() 濡傛灉鏄湡姝g殑 User 瀵硅薄锛岃繑鍥炲兼亽涓 True 銆 鐢ㄤ簬妫鏌ョ敤鎴锋槸鍚﹀凡缁忛氳繃浜嗚璇併傞氳繃璁よ瘉骞朵笉鎰忓懗鐫 鐢ㄦ埛鎷ユ湁浠讳綍鏉冮檺锛岀敋鑷充篃涓嶆鏌ヨ鐢ㄦ埛鏄惁澶勪簬婵娲荤姸 鎬侊紝杩欏彧鏄〃鏄庣敤鎴锋垚鍔熺殑閫氳繃浜嗚璇併
is_anonymous() 濡傛灉鏄釜 AnonymousUser 锛岃繑鍥炲间负 True 锛 濡傛灉鏄 User 瀵硅薄锛岃繑鍥炲间负 False 銆備竴鑸潵 璇达紝 is_authenticated() 浼氭瘮杩欎釜鏂规硶鏇村父鐢ㄤ簺銆
get_full_name() 杩斿洖鍊间负锛 first_name 鍔犱笂 last_name 锛屼互 绌烘牸鍒嗛殧銆
set_password(passwd) 灏嗙敤鎴风殑瀵嗙爜璁剧疆涓虹粰瀹氱殑瀛楃涓诧紝瀹為檯瀵嗙爜宸茶鍝堝笇 澶勭悊銆傝繖鏃跺苟涓嶄細鐪熸淇濆瓨 User 瀵硅薄銆
check_password(passwd) 濡傛灉缁欏畾鐨勫瓧绗︿覆閫氳繃浜嗗瘑鐮佹鏌ワ紝杩斿洖 True 銆 瀵嗙爜姣旇緝宸茶繘琛屼簡鍝堝笇澶勭悊銆
get_group_permissions() 杩斿洖鐢ㄦ埛閫氳繃鎵灞炵粍鑾峰緱鐨勬潈闄愬垪琛
get_all_permissions() 杩斿洖鐢ㄦ埛閫氳繃鎵灞炵粍鍜岀敤鎴疯嚜韬潈闄愭墍鑾峰緱鐨勬墍鏈夋潈闄 鍒楄〃銆
has_perm(perm) 濡傛灉鐢ㄦ埛鎷ユ湁缁欏畾鐨勬潈闄愶紝杩斿洖 Trueperm 搴斿舰濡 "package.codename" 鐨勬牸寮忋傚鏋滅敤鎴峰浜 闈炴縺娲荤姸鎬侊紝鍒欐绘槸杩斿洖 False
has_perms(perm_list) 濡傛灉鐢ㄦ埛鎷ユ湁鎵鏈夌粰瀹氱殑鏉冮檺锛岃繑鍥 True 銆 濡傛灉鐢ㄦ埛澶勪簬闈炴縺娲荤姸鎬侊紝鍒欐绘槸杩斿洖 False
has_module_perms(app_label) 濡傛灉鐢ㄦ埛鎷ユ湁浠讳綍缁欏畾 app_label 鐨勬潈闄愶紝杩斿洖 True 銆傚鏋滅敤鎴峰浜庨潪婵娲荤姸鎬侊紝鍒欐绘槸杩斿洖 False
get_and_delete_messages() 杩斿洖鐢ㄦ埛鐨 Message 瀵硅薄鍒楄〃锛屽苟浠庨槦鍒椾腑鍒犻櫎銆
email_user(subj, msg) 缁欑敤鎴峰彂閫佺數瀛愰偖浠讹紝鐢 DEFAULT_FROM_EMAIL 鐨勮 缃綔涓哄彂浠朵汉銆備篃鍙互鐢ㄧ3涓弬鏁 from_email 鏉 瑕嗙洊璁剧疆銆
get_profile() 杩斿洖鐢ㄦ埛鐨勭綉绔欒嚜瀹氫箟profile锛岃瑙丳rofile绔犺妭

Finally, User objects have two many-to-many fields: groups and permissions . User objects can access their related objects in the same way as any other many-to-many field:

鏈鍚庯紝 User 瀵硅薄鏈変袱涓瀵瑰鐨勫睘鎬э細 groupspermissionsUser 瀵硅薄鍙互 璞′娇鐢ㄥ叾浠栧瀵瑰灞炴х殑鏂规硶涓鏍蜂娇鐢ㄥ畠浠

# Set a user's groups:
myuser.groups = group_list

# Add a user to some groups:
myuser.groups.add(group1, group2,...)

# Remove a user from some groups:
myuser.groups.remove(group1, group2,...)

# Remove a user from all groups:
myuser.groups.clear()

# Permissions work the same way
myuser.permissions = permission_list
myuser.permissions.add(permission1, permission2, ...)
myuser.permissions.remove(permission1, permission2, ...)
myuser.permissions.clear()

Logging In and Out

鐧诲綍鍜岄鍑

Django provides built-in view functions for handling logging in and out (and a few other nifty tricks), but before we get to those, lets take a look at how to log users in and out by hand. Django provides two functions to perform these actions in django.contrib.auth : authenticate() and login() .

Django 鎻愪緵鍐呯疆鐨勮鍥(view)鍑芥暟鐢ㄤ簬澶勭悊鐧诲綍鍜岄鍑 (浠ュ強鍏朵粬濂囨妧娣阀)锛屼絾鍦ㄥ紑濮嬪墠锛屾垜浠潵鐪嬬湅濡備綍鎵嬪伐鐧诲綍鍜岄鍑猴紝Django 鍦 django.contrib.auth 涓彁渚涗簡涓や釜鍑芥暟鏉ュ鐞嗚繖浜涗簨鎯呪斺 authenticate()login()

To authenticate a given username and password, use authenticate() . It takes two keyword arguments, username and password , and it returns a User object if the password is valid for the given username. If the password is invalid, authenticate() returns None :

璁よ瘉缁欏嚭鐨勭敤鎴峰悕鍜屽瘑鐮侊紝浣跨敤 authenticate() 鍑芥暟銆傚畠鎺ュ彈涓や釜鍙傛暟锛岀敤鎴峰悕 username 鍜 瀵嗙爜 password 锛屽苟鍦ㄥ瘑鐮佸鐢ㄧ粰鍑虹殑鐢ㄦ埛鍚嶆槸鍚堟硶鐨勬儏鍐典笅杩斿洖涓涓 User 瀵硅薄銆傚綋缁欏嚭鐨勫瘑鐮佷笉鍚堟硶鐨勬椂鍊 authenticate() 鍑芥暟杩斿洖 None

>>> from django.contrib import auth
>>> user = auth.authenticate(username='john', password='secret')
>>> if user is not None:
...     print "Correct!"
... else:
...     print "Oops, that's wrong!"

authenticate() only verifies a users credentials. To log in a user, use login() . It takes an HttpRequest object and a User object and saves the users ID in the session, using Djangos session framework.

authenticate() 鍙槸楠岃瘉涓涓敤鎴风殑璇佷功鑰屽凡銆傝岃鐧诲綍涓涓敤鎴凤紝浣跨敤 login() 銆傝鍑芥暟鎺ュ彈涓涓 HttpRequest 瀵硅薄鍜屼竴涓 User 瀵硅薄浣滀负鍙傛暟骞朵娇鐢―jango鐨勪細璇濓紙 session 锛夋鏋舵妸鐢ㄦ埛鐨処D淇濆瓨鍦ㄨ浼氳瘽涓

This example shows how you might use both authenticate() and login() within a view function:

涓嬮潰鐨勪緥瀛愭紨绀轰簡濡備綍鍦ㄤ竴涓鍥句腑鍚屾椂浣跨敤 authenticate()login() 鍑芥暟锛

from django.contrib import auth

def login(request):
    username = request.POST['username']
    password = request.POST['password']
    user = auth.authenticate(username=username, password=password)
    if user is not None and user.is_active:
        # Correct password, and the user is marked "active"
        auth.login(request, user)
        # Redirect to a success page.
        return HttpResponseRedirect("/account/loggedin/")
    else:
        # Show an error page
        return HttpResponseRedirect("/account/invalid/")

To log out a user, use django.contrib.auth.logout() within your view. It takes an HttpRequest object and has no return value:

娉ㄩ攢涓涓敤鎴凤紝鍦ㄤ綘鐨勮鍥句腑浣跨敤 django.contrib.auth.logout() 銆傝鍑芥暟鎺ュ彈涓涓 HttpRequest 瀵硅薄浣滀负鍙傛暟锛屾病鏈夎繑鍥炲笺

from django.contrib import auth

def logout(request):
    auth.logout(request)
    # Redirect to a success page.
    return HttpResponseRedirect("/account/loggedout/")

Note that logout() doesnt throw any errors if the user wasnt logged in.

娉ㄦ剰锛屽嵆浣跨敤鎴锋病鏈夌櫥褰曪紝 logout() 涔熶笉浼氭姏鍑轰换浣曞紓甯搞

In practice, you usually will not need to write your own login/logout functions; the authentication system comes with a set of views for generically handling logging in and out.

鍦ㄥ疄闄呬腑锛屼綘涓鑸笉闇瑕佽嚜宸卞啓鐧诲綍/鐧诲嚭鐨勫嚱鏁帮紱璁よ瘉绯荤粺鎻愪緵浜嗕竴绯讳緥瑙嗗浘鐢ㄦ潵澶勭悊鐧诲綍鍜岀櫥鍑恒

The first step in using the authentication views is to wire them up in your URLconf. Youll need to add this snippet:

浣跨敤璁よ瘉瑙嗗浘鐨勭涓姝ユ槸鎶婂畠浠啓鍦ㄤ綘鐨刄RLconf涓 浣犻渶瑕佽繖鏍峰啓锛

from django.contrib.auth.views import login, logout

urlpatterns = patterns('',
    # existing patterns here...
    (r'^accounts/login/$',  login),
    (r'^accounts/logout/$', logout),
)

/accounts/login/ and /accounts/logout/ are the default URLs that Django uses for these views.

/accounts/login//accounts/logout/ 鏄疍jango鎻愪緵鐨勮鍥剧殑榛樿URL銆

By default, the login view renders a template at registration/login.html (you can change this template name by passing an extra view argument ,``template_name``). This form needs to contain a username and a password field. A simple template might look like this:

缂虹渷鎯呭喌涓嬶紝 login 瑙嗗浘娓叉煋 registragiton/login.html 妯℃澘(鍙互閫氳繃瑙嗗浘鐨勯澶栧弬鏁 template_name 淇敼杩欎釜妯℃澘鍚嶇О)銆傝繖涓〃鍗曞繀椤诲寘鍚 usernamepassword 鍩熴傚涓嬬ず渚嬶細

{% extends "base.html" %}

{% block content %}

  {% if form.errors %}
    <p class="error">Sorry, that's not a valid username or password</p>
  {% endif %}

  <form action='.' method='post'>
    <label for="username">User name:</label>
    <input type="text" name="username" value="" id="username">
    <label for="password">Password:</label>
    <input type="password" name="password" value="" id="password">

    <input type="submit" value="login" />
    <input type="hidden" name="next" value="{{ next|escape }}" />
  <form action='.' method='post'>

{% endblock %}

If the user successfully logs in, he or she will be redirected to /accounts/profile/ by default. You can override this by providing a hidden field called next with the URL to redirect to after logging in. You can also pass this value as a GET parameter to the login view and it will be automatically added to the context as a variable called next that you can insert into that hidden field.

濡傛灉鐢ㄦ埛鐧诲綍鎴愬姛锛岀己鐪佷細閲嶅畾鍚戝埌 /accounts/profile 銆傝〃鍗曚腑鏈変竴涓猦idden瀛楁鍙 next 锛屽彲浠ョ敤鍦ㄧ櫥褰曞悗鎸囧畾url銆備篃鍙互鎶婅繖涓硷紙鎸囧畾鐨剈rl锛変綔涓 GET 鍙傛暟浼犻掔粰login瑙嗗浘锛岃繖涓弬鏁颁細鎴愪负Context涓悕涓 next 鐨勫彉閲忥紝浣犲彲浠ユ妸杩欎釜鍙橀噺璁剧疆缁欒〃鍗曚腑瀵瑰簲鐨勯殣鍚瓧娈点

The logout view works a little differently. By default it renders a template at registration/logged_out.html (which usually contains a Youve successfully logged out message). However, you can call the view with an extra argument, next_page , which will instruct the view to redirect after a logout.

logout瑙嗗浘鏈変竴浜涗笉鍚屻傜己鐪佺殑瀹冩覆鏌 registration/logged_out.html 妯℃澘锛堣繖涓鍥句竴鑸寘鍚綘宸茬粡鎴愬姛閫鍑虹殑淇℃伅锛夈傝鍥句腑杩樺彲浠ュ寘鍚竴涓弬鏁 next_page 鐢ㄤ簬閫鍑哄悗閲嶅畾鍚戙

Limiting Access to Logged-in Users

闄愬埗宸茬櫥褰曠敤鎴风殑璁块棶

Of course, the reason were going through all this trouble is so we can limit access to parts of our site.

鏈夊緢澶氬師鍥犻渶瑕佹帶鍒剁敤鎴疯闂珯鐐圭殑鏌愰儴鍒嗐

The simple, raw way to limit access to pages is to check request.user.is_authenticated() and redirect to a login page:

涓涓畝鍗曞師濮嬬殑闄愬埗鏂规硶鏄鏌 request.user.is_authenticated() ,鐒跺悗閲嶅畾鍚戝埌鐧婚檰椤甸潰锛

from django.http import HttpResponseRedirect

def my_view(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/login/?next=%s' % request.path)
    # ...

or perhaps display an error message:

鎴栬呮樉绀轰竴涓嚭閿欎俊鎭細

def my_view(request):
    if not request.user.is_authenticated():
        return render_to_response('myapp/login_error.html')
    # ...

As a shortcut, you can use the convenient login_required decorator:

浣滀负涓涓揩鎹锋柟寮, 浣犲彲浠ヤ娇鐢ㄤ究鎹风殑 login_required 淇グ绗:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    # ...

login_required does the following:

login_required 鍋氫笅闈㈢殑浜嬫儏:

  • If the user isnt logged in, redirect to /accounts/login/ , passing the current absolute URL in the query string as next , for example: /accounts/login/?next=/polls/3/ .

  • 濡傛灉鐢ㄦ埛娌℃湁鐧诲綍, 閲嶅畾鍚戝埌 /accounts/login/ , 鎶婂綋鍓嶇粷瀵筓RL浣滀负 next 鍦ㄦ煡璇㈠瓧绗︿覆涓紶閫掕繃鍘, 渚嬪: /accounts/login/?next=/polls/3/ .

  • If the user is logged in, execute the view normally. The view code can then assume that the user is logged in.

  • 濡傛灉鐢ㄦ埛宸茬粡鐧诲綍, 姝e父鍦版墽琛岃鍥惧嚱鏁. 瑙嗗浘浠g爜灏卞彲浠ュ亣瀹氱敤鎴峰凡缁忕櫥褰曚簡.

Limiting Access to Users Who Pass a Test

瀵归氳繃娴嬭瘯鐨勭敤鎴烽檺鍒惰闂

Limiting access based on certain permissions or some other test, or providing a different location for the login view works essentially the same way.

闄愬埗璁块棶鍙互鍩轰簬鏌愮鏉冮檺锛屾煇浜涙鏌ユ垨鑰呬负login瑙嗗浘鎻愪緵涓嶅悓鐨勪綅缃紝杩欎簺瀹炵幇鏂瑰紡澶ц嚧鐩稿悓

The raw way is to run your test on request.user in the view directly. For example, this view checks to make sure the user is logged in and has the permission polls.can_vote (more about how permissions works follows):

涓鑸殑鏂规硶鏄洿鎺ュ湪瑙嗗浘鐨 request.user 涓婅繍琛屾鏌ャ備緥濡傦紝涓嬮潰瑙嗗浘妫鏌ョ敤鎴风櫥闄嗗苟鏄惁鏈 polls.can_vote 鐨勬潈闄愶細

def vote(request):
    if request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
        # vote here
    else:
        return HttpResponse("You can't vote in this poll.")

Again, Django provides a shortcut called user_passes_test . It takes arguments and generates a specialized decorator for your particular situation:

骞朵笖Django鏈変竴涓О涓 user_passes_test 鐨勭畝娲佹柟寮忋傚畠鏍规嵁鎯呭喌浣跨敤鍙傛暟骞朵笖浜х敓鐗规畩瑁呴グ绗︺

def user_can_vote(user):
    return user.is_authenticated() and user.has_perm("polls.can_vote")

@user_passes_text(user_can_vote, login_url="/login/")
def vote(request):
    # Code here can assume a logged-in user with the correct permission.
    ...

user_passes_test takes one required argument: a callable that takes a User object and returns True if the user is allowed to view the page. Note that user_passes_test does not automatically check that the User is authenticated; you should do that yourself.

user_passes_test 浣跨敤涓涓繀闇鐨勫弬鏁帮細涓涓彲璋冪敤鐨勬柟娉曪紝褰撳瓨鍦 User 瀵硅薄骞跺綋姝ょ敤鎴峰厑璁告煡鐪嬭椤甸潰鏃惰繑鍥 True 銆 娉ㄦ剰 user_passes_test 涓嶄細鑷姩妫鏌 User 鏄惁璁よ瘉锛屼綘搴旇鑷繁鍋氳繖浠朵簨銆

In this example were also showing the second optional argument, login_url , which lets you specify the URL for your login page (/accounts/login/ by default).

渚嬪瓙涓垜浠篃灞曠ず浜嗙浜屼釜鍙夌殑鍙傛暟 login_url 锛屽畠璁╀綘鎸囧畾浣犵殑鐧诲綍椤甸潰鐨刄RL锛堥粯璁や负 /accounts/login/ 锛夈

Since its a relatively common task to check whether a user has a particular permission, Django provides a shortcut for that case: the permission_required() decorator. Using this decorator, the earlier example can be written as follows:

鏃㈢劧妫鏌ョ敤鎴锋槸鍚︽湁涓涓壒娈婃潈闄愭槸鐩稿甯歌鐨勪换鍔★紝Django涓鸿繖绉嶆儏褰㈡彁渚涗簡涓涓嵎寰勶細 permission_required() 瑁呴グ鍣 浣跨敤杩欎釜瑁呴グ鍣紝鍓嶉潰鐨勪緥瀛愬彲浠ヨ繖鏍峰啓:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url="/login/")
def vote(request):
    # ...

Note that permission_required() also takes an optional login_url parameter, which also defaults to '/accounts/login/' .

娉ㄦ剰, permission_required() 涔熸湁涓涓彲閫夌殑 login_url 鍙傛暟, 杩欎釜鍙傛暟榛樿涓 '/accounts/login/'

Limiting Access to Generic Views

闄愬埗閫氱敤瑙嗗浘鐨勮闂

One of the most frequently asked questions on the Django users list deals with limiting access to a generic view. To pull this off, youll need to write a thin wrapper around the view and point your URLconf to your wrapper instead of the generic view itself:

鍦―jango鐢ㄦ埛閭欢鍒楄〃涓棶鍒版渶澶氱殑闂鏄叧浜庡閫氱敤瑙嗗浘鐨勯檺鍒舵ц闂備负瀹炵幇杩欎釜鍔熻兘锛屼綘闇瑕佽嚜宸卞寘瑁呰鍥撅紝骞朵笖鍦║RLconf涓紝灏嗕綘鑷繁鐨勭増鏈浛鎹㈤氱敤瑙嗗浘锛

from dango.contrib.auth.decorators import login_required
from django.views.generic.date_based import object_detail

@login_required
def limited_object_detail(*args, **kwargs):
    return object_detail(*args, **kwargs)

You can, of course, replace login_required with any of the other limiting decorators.

褰撶劧, 浣犲彲浠ョ敤浠讳綍鍏朵粬闄愬畾淇グ绗︽潵鏇挎崲 login_required

Managing Users, Permissions, and Groups

绠$悊 Users, Permissions 鍜 Groups

The easiest way by far to manage the auth system is through the admin interface. Chapter 6 discusses how to use Djangos admin interface to edit users and control their permissions and access, and most of the time youll just use that interface.

绠$悊璁よ瘉绯荤粺鏈绠鍗曠殑鏂规硶鏄氳繃绠$悊鐣岄潰銆 绗叚绔犺璁轰簡鎬庢牱浣跨敤Django鐨勭鐞嗙晫闈㈡潵缂栬緫鐢ㄦ埛鍜屾帶鍒朵粬浠殑鏉冮檺鍜屽彲璁块棶鎬э紝骞朵笖澶у鏁版椂闂翠綘閮戒細鍙娇鐢ㄨ繖涓晫闈€

However, there are low-level APIs you can delve into when you need absolute control, and we discuss these in the sections that follow.

鐒惰岋紝褰撲綘闇瑕佺粷瀵圭殑鎺у埗鏉冪殑鏃跺欙紝鏈変竴浜涗綆灞 API 闇瑕佹繁鍏ヤ笓鐮旓紝鎴戜滑灏嗗湪涓嬮潰鐨勭珷鑺備腑璁ㄨ瀹冧滑銆

Creating Users
鍒涘缓鐢ㄦ埛

Create users with the create_user helper function:

浣跨敤 create_user 杈呭姪鍑芥暟鍒涘缓鐢ㄦ埛:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user(username='john',
...                                 email='jlennon@beatles.com',
...                                 password='glass onion')

At this point, user is a User instance ready to be saved to the database (create_user() doesnt actually call save() itself). You can continue to change its attributes before saving, too:

鍦ㄨ繖閲岋紝 userUser 绫荤殑涓涓疄渚嬶紝鍑嗗鐢ㄤ簬鍚戞暟鎹簱涓瓨鍌ㄦ暟鎹 create_user() 鍑芥暟骞舵病鏈夊湪鏁版嵁搴撲腑鍒涘缓璁板綍锛屽湪淇濆瓨鏁版嵁涔嬪墠锛屼綘浠嶇劧鍙互缁х画淇敼瀹冪殑灞炴у笺

>>> user.is_staff = True
>>> user.save()
Changing Passwords
淇敼瀵嗙爜

You can change a password with set_password() :

浣犲彲浠ヤ娇鐢 set_password() 鏉ヤ慨鏀瑰瘑鐮侊細

>>> user = User.objects.get(username='john')
>>> user.set_password('goo goo goo joob')
>>> user.save()

Dont set the password attribute directly unless you know what youre doing. The password is actually stored as a salted hash and thus cant be edited directly.

闄ら潪浣犳竻妤氱殑鐭ラ亾鑷繁鍦ㄥ仛浠涔堬紝鍚﹀垯涓嶈鐩存帴淇敼 password 灞炴с傚叾涓繚瀛樼殑鏄瘑鐮佺殑 鍔犲叆salt鐨刪ash鍊 锛屾墍浠ヤ笉鑳界洿鎺ョ紪杈戙

More formally, the password attribute of a User object is a string in this format:

涓鑸潵璇达紝 User 瀵硅薄鐨 password 灞炴ф槸涓涓瓧绗︿覆锛屾牸寮忓涓嬶細

hashtype$salt$hash

Thats a hash type, the salt, and the hash itself, separated by the dollar sign ($) character.

杩欐槸鍝堝笇绫诲瀷锛宻alt鍜屽搱甯屾湰韬紝鐢ㄧ編鍏冪鍙凤紙$锛夊垎闅斻

hashtype is either sha1 (default) or md5 , the algorithm used to perform a one-way hash of the password. salt is a random string used to salt the raw password to create the hash, for example:

hashtypesha1 锛堥粯璁わ級鎴栬 md5 锛屽畠鏄敤鏉ュ鐞嗗崟鍚戝瘑鐮佸搱甯岀殑绠楁硶锛孲alt鏄竴涓敤鏉ュ姞瀵嗗師濮嬪瘑鐮佹潵鍒涘缓鍝堝笇鐨勯殢鏈哄瓧绗︿覆锛屼緥濡:

sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4

The User.set_password() and User.check_password() functions handle the setting and checking of these values behind the scenes.

User.set_password()User.check_password() 鍑芥暟鍦ㄥ悗鍙板鐞嗗拰妫鏌ヨ繖浜涘笺

Is a Salted Hash Some Kind of Drug?

涓涓姞鍏alt鐨勫搱甯岀畻娉曟槸鏌愮姣掑搧鍚楋紵

No, a salted hash has nothing to do with marijuana; its actually a common way to securely store passwords. A hash is a one-way cryptographic functionthat is, you can easily compute the hash of a given value, but its nearly impossible to take a hash and reconstruct the original value.

涓嶆槸锛屼竴涓 鍔犲叆salt鍊肩殑鍝堝笇绠楁硶 鍙笉鏄粈涔堟瘨鍝侊紱浜嬪疄涓婂畠鏄竴绉嶇‘淇濆瘑鐮佸瓨鍌ㄥ畨鍏ㄧ殑甯哥敤鏂规硶銆備竴娆 鍝堝笇 鏄竴娆″崟鍚戠殑鍔犲瘑杩囩▼锛屼綘鑳藉鏄撳湴璁$畻鍑轰竴涓粰瀹氬肩殑鍝堝笇鐮侊紝浣嗘槸鍑犱箮涓嶅彲鑳戒粠涓涓搱甯岀爜瑙e嚭瀹冪殑鍘熷笺

If we stored passwords as plain text, anyone who got their hands on the password database would instantly know everyones password. Storing passwords as hashes reduces the value of a compromised database.

濡傛灉鎴戜滑浠ユ櫘閫氭枃鏈瓨鍌ㄥ瘑鐮,浠讳綍鑳借繘鍏ユ暟鎹簱鐨勪汉閮借兘杞绘槗鐨勮幏鍙栨瘡涓汉鐨勫瘑鐮併備娇鐢ㄥ搱甯屾柟寮忔潵瀛樺偍瀵嗙爜鐩稿簲鐨勫噺灏戜簡鏁版嵁搴撴硠闇插瘑鐮佺殑鍙兘銆

However, an attacker with the password database could still run a brute- force attack, hashing millions of passwords and comparing those hashes against the stored values. This takes some time, but less than you might thinkcomputers are incredibly fast.

鐒惰岋紝鏀诲嚮鑰呬粛鐒跺彲浠ヤ娇鐢 鏆村姏鐮磋В 浣跨敤涓婄櫨涓囦釜瀵嗙爜涓庡瓨鍌ㄧ殑鍊煎姣旀潵鑾峰彇鏁版嵁搴撳瘑鐮侊紝杩欓渶瑕佽姳涓浜涙椂闂达紝浣嗘槸鏅鸿兘鐢佃剳鎯婁汉鐨勯熷害瓒呭嚭浜嗕綘鐨勬兂璞

Worse, there are publicly available rainbow tables , or databases of precomputed hashes of millions of passwords. With a rainbow table, an attacker can break most passwords in seconds.

鏇寸碂绯曠殑鏄垜浠彲浠ュ叕寮鍦板緱鍒 rainbow tables 锛堜竴绉嶆毚鍔涘瘑鐮佺牬瑙h〃锛夋垨棰勫鏈変笂鐧句竾鍝堝笇瀵嗙爜鍊肩殑鏁版嵁搴撱備娇鐢╮ainbow tables鍙互鍦ㄥ嚑绉掍箣鍐呭氨鑳芥悶瀹氭渶澶嶆潅鐨勪竴涓瘑鐮併

Adding a salt basically an initial random valueto the stored hash adds another layer of difficulty to breaking passwords. Since salts differ from password to password, they also prevent the use of a rainbow table, thus forcing attackers to fall back on a brute-force attack, itself made more difficult by the extra entropy added to the hash by the salt.

鍦ㄥ瓨鍌ㄧ殑hash鍊肩殑鍩虹涓婏紝鍔犲叆 salt 鍊硷紙涓涓殢鏈哄硷級锛屽鍔犱簡瀵嗙爜鐨勫己搴︼紝浣垮緱鐮磋В鏇村姞鍥伴毦銆傚洜涓烘瘡涓瘑鐮佺殑salt鍊奸兘涓嶇浉鍚岋紝杩欎篃闄愬埗浜唕ainbow table鐨勪娇鐢紝浣垮緱鏀诲嚮鑰呭彧鑳戒娇鐢ㄦ渶鍘熷鐨勬毚鍔涚牬瑙f柟娉曘傝屽姞鍏ョ殑salt鍊间娇寰梙ash鐨勭喌杩涗竴姝ヨ幏寰楀鍔狅紝浣垮緱鏆村姏鐮磋В鐨勯毦搴﹀張杩涗竴姝ュ姞澶с

While salted hashes arent absolutely the most secure way of storing passwords, theyre a good middle ground between security and convenience.

鍔犲叆salt鍊煎緱hash骞朵笉鏄粷瀵瑰畨鍏ㄧ殑瀛樺偍瀵嗙爜鐨勬柟娉曪紝鐒惰屽湪瀹夊叏鍜屾柟渚夸箣闂存湁寰堝ぇ鐨勪腑闂村湴甯﹂渶瑕佹垜浠潵鍋氬喅瀹氥

Handling Registration

澶勭悊娉ㄥ唽

We can use these low-level tools to create views that allow users to sign up. Nearly every developer wants to implement registration differently, so Django leaves writing a registration view up to you. Luckily, its pretty easy.

鎴戜滑鍙互浣跨敤杩欎簺搴曞眰宸ュ叿鏉ュ垱寤哄厑璁哥敤鎴锋敞鍐岀殑瑙嗗浘銆傛渶杩戞瘡涓紑鍙戜汉鍛橀兘甯屾湜瀹炵幇鍚勮嚜涓嶅悓鐨勬敞鍐屾柟娉曪紝鎵浠jango鎶婂啓涓涓敞鍐岃鍥剧殑宸ヤ綔鐣欑粰浜嗕綘銆傚垢杩愮殑鏄紝杩欏緢瀹规槗銆

At its simplest, we could provide a small view that prompts for the required user information and creates those users. Django provides a built-in form you can use for this purpose, which well use in this example:

浣滀负杩欎釜浜嬫儏鐨勬渶绠鍖栧鐞, 鎴戜滑鍙互鎻愪緵涓涓皬瑙嗗浘, 鎻愮ず涓浜涘繀椤荤殑鐢ㄦ埛淇℃伅骞跺垱寤鸿繖浜涚敤鎴. Django涓烘鎻愪緵浜嗗彲鐢ㄧ殑鍐呯疆琛ㄥ崟, 鍦ㄤ笅闈㈣繖涓緥瀛愪腑寰堝ソ鍦颁娇鐢ㄤ簡:

from django import oldforms as forms
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.contrib.auth.forms import UserCreationForm

def register(request):
    form = UserCreationForm()

    if request.method == 'POST':
        data = request.POST.copy()
        errors = form.get_validation_errors(data)
        if not errors:
            new_user = form.save(data)
            return HttpResponseRedirect("/books/")
    else:
        data, errors = {}, {}

    return render_to_response("registration/register.html", {
        'form' : forms.FormWrapper(form, data, errors)
    })

This form assumes a template named registration/register.html . Heres an example of what that template might look like:

杩欎釜琛ㄥ崟鏋勬兂浜嗕竴涓彨 registration/register.html 鐨勬ā鏉. 杩欓噷鏄竴涓繖涓ā鏉跨殑鍙兘鐨勬牱瀛愮殑渚嬪瓙:

{% extends "base.html" %}

{% block title %}Create an account{% endblock %}

{% block content %}
  <h1>Create an account</h1>
  <form action="." method="post">
    {% if form.error_dict %}
      <p class="error">Please correct the errors below.</p>
    {% endif %}

    {% if form.username.errors %}
      {{ form.username.html_error_list }}
    {% endif %}
    <label for="id_username">Username:</label> {{ form.username }}

    {% if form.password1.errors %}
      {{ form.password1.html_error_list }}
    {% endif %}
    <label for="id_password1">Password: {{ form.password1 }}

    {% if form.password2.errors %}
      {{ form.password2.html_error_list }}
    {% endif %}
    <label for="id_password2">Password (again): {{ form.password2 }}

    <input type="submit" value="Create the account" />
  </label>
{% endblock %}

Note

澶囨敞

django.contrib.auth.forms.UserCreationForm is, at the time of publication, an oldforms Form. See http://www.djangoproject.com/documentation/0.96/forms/ for details on oldforms. The transition to newforms, as covered in Chapter 7, will be completed in the near future.

鍦ㄦ湰涔﹀嚭鐗堜箣鏃, django.contrib.auth.forms.UserCreationForm 鏄竴涓 oldforms 琛ㄥ崟. 鍙傜湅 http://www.djangoproject.com/documentation/0.96/forms/ 鍙互鑾峰彇鏈夊叧 oldforms 鐨勮缁嗕俊鎭. 杞崲鍒版湁鍏 newforms 鐨勫唴瀹瑰湪绗7绔犱腑灏嗕細璁茶堪, newforms 鍔熻兘 灏嗕細鍦ㄤ笉杩滅殑灏嗘潵瀹屾垚.

Using Authentication Data in Templates

鍦ㄦā鏉夸腑浣跨敤璁よ瘉鏁版嵁

The current logged-in user and his or her permissions are made available in the template context when you use RequestContext (see Chapter 10).

褰撳墠鐧诲叆鐨勭敤鎴蜂互鍙婁粬锛堝ス锛夌殑鏉冮檺鍙互閫氳繃 RequestContext 鍦ㄦā鏉跨殑context涓娇鐢紙璇﹁绗10绔狅級銆

Note

澶囨敞

Technically, these variables are only made available in the template context if you use RequestContext and your TEMPLATE_CONTEXT_PROCESSORS setting contains "django.core.context_processors.auth" , which is the default. Again, see Chapter 10 for more information.

浠庢妧鏈笂鏉ヨ锛屽彧鏈夊綋浣犱娇鐢ㄤ簡 RequestContext 骞朵笖 TEMPLATE_CONTEXT_PROCESSORS 璁剧疆鍖呭惈浜 "django.core.context_processors.auth" 锛堥粯璁ゆ儏鍐靛氨鏄姝わ級鏃讹紝杩欎簺鍙橀噺鎵嶈兘鍦ㄦā鏉縞ontext涓娇鐢ㄣ傛洿璇︾粏鐨勫唴瀹癸紝涔熻鍙傝冪10绔犮

When using RequestContext , the current user (either a User instance or an AnonymousUser instance) is stored in the template variable {{ user }} :

褰撲娇鐢 RequestContext 鏃, 褰撳墠鐢ㄦ埛 (鏄竴涓 User 瀹炰緥鎴栦竴涓 AnonymousUser 瀹炰緥) 瀛樺偍鍦ㄦā鏉垮彉閲 {{ user }} 涓:

{% if user.is_authenticated %}
  <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
  <p>Welcome, new user. Please log in.</p>
{% endif %}

This users permissions are stored in the template variable {{ perms }} . This is a template-friendly proxy to a couple of permission methods described shortly.

杩欎簺鐢ㄦ埛鐨勬潈闄愪俊鎭瓨鍌ㄥ湪 {{ perms }} 妯℃澘鍙橀噺涓傝繖鏄竴涓湪妯℃澘涓娇鐢ㄥ緢鏂逛究鐨勪唬鐞嗭紝鍏朵腑鍖呭惈涓浜涙潈闄愮浉鍏冲嚱鏁扮殑绠鍐欍

There are two ways you can use this perms object. You can use something like {{ perms.polls }} to check if the user has any permissions for some given application, or you can use something like {{ perms.polls.can_vote }} to check if the user has a specific permission.

浣犳湁涓ょ鏂瑰紡鏉ヤ娇鐢 perms 瀵硅薄銆備綘鍙互浣跨敤绫讳技浜 {{ perms.polls }} 鐨勫舰寮忔潵妫鏌ワ紝瀵逛簬鏌愪釜鐗瑰畾鐨勫簲鐢紝涓涓敤鎴锋槸鍚﹀叿鏈 浠绘剰 鏉冮檺锛涗綘涔熷彲浠ヤ娇鐢 {{ perms.polls.can_vote }} 杩欐牱鐨勫舰寮忥紝鏉ユ鏌ヤ竴涓敤鎴锋槸鍚︽嫢鏈夌壒瀹氱殑鏉冮檺銆

Thus, you can check permissions in template {% if %} statements:

杩欐牱浣犲氨鍙互鍦ㄦā鏉夸腑鐨 {% if %} 璇彞涓鏌ユ潈闄:

{% if perms.polls %}
  <p>You have permission to do something in the polls app.</p>
  {% if perms.polls.can_vote %}
    <p>You can vote!</p>
  {% endif %}
{% else %}
  <p>You don't have permission to do anything in the polls app.</p>
{% endif %}

The Other Bits: Permissions, Groups, Messages, and Profiles

鍏朵粬涓浜涘姛鑳斤細鏉冮檺锛岀粍锛屾秷鎭拰妗f

There are a few other bits of the authentication framework that weve only dealt with in passing. Well take a closer look at them in the following sections.

鍦ㄨ璇佹鏋朵腑杩樻湁鍏朵粬鐨勪竴浜涘姛鑳姐傛垜浠細鍦ㄦ帴涓嬫潵鐨勫嚑涓儴鍒嗕腑杩涗竴姝ュ湴浜嗚В瀹冧滑銆

Permissions

鏉冮檺

Permissions are a simple way to mark users and groups as being able to perform some action. They are usually used by the Django admin site, but you can easily use them in your own code.

鏉冮檺鍙互寰堟柟渚垮湴鏍囪瘑鐢ㄦ埛鍜岀敤鎴风粍鍙互鎵ц鐨勬搷浣溿傚畠浠Django鐨刟dmin绠$悊绔欑偣鎵浣跨敤锛屼綘涔熷彲浠ュ湪浣犺嚜宸辩殑浠g爜涓娇鐢ㄥ畠浠

The Django admin site uses permissions as follows:

Django鐨刟dmin绔欑偣濡備笅浣跨敤鏉冮檺锛

  • Access to view the add form, and add an object is limited to users with the add permission for that type of object.

  • 鍙湁璁剧疆浜 add 鏉冮檺鐨勭敤鎴锋墠鑳戒娇鐢ㄦ坊鍔犺〃鍗曪紝娣诲姞瀵硅薄鐨勮鍥俱

  • Access to view the change list, view the change form, and change an object is limited to users with the change permission for that type of object.

  • 鍙湁璁剧疆浜 change 鏉冮檺鐨勭敤鎴锋墠鑳戒娇鐢ㄥ彉鏇村垪琛紝鍙樻洿琛ㄦ牸锛屽彉鏇村璞$殑瑙嗗浘銆

  • Access to delete an object is limited to users with the delete permission for that type of object.

  • 鍙湁璁剧疆浜 delete 鏉冮檺鐨勭敤鎴锋墠鑳藉垹闄や竴涓璞°

Permissions are set globally per type of object, not per specific object instance. For example, its possible to say Mary may change news stories, but its not currently possible to say Mary may change news stories, but only the ones she created herself or Mary may only change news stories that have a certain status, publication date, or ID.

鏉冮檺鏄牴鎹瘡涓涓被鍨嬬殑瀵硅薄鑰岃缃殑锛屽苟涓嶅叿浣撳埌瀵硅薄鐨勭壒瀹氬疄渚嬨備緥濡傦紝鎴戜滑鍙互鍏佽Mary鏀瑰彉鏂版晠浜嬶紝浣嗘槸鐩墠杩樹笉鍏佽璁剧疆Mary鍙兘鏀瑰彉鑷繁鍒涘缓鐨勬柊鏁呬簨锛屾垨鑰呮牴鎹粰瀹氱殑鐘舵侊紝鍑虹増鏃ユ湡鎴栬匢D鍙锋潵閫夋嫨鏉冮檺銆

These three basic permissionsadd, change, and deleteare automatically created for each Django model that has a class Admin . Behind the scenes, these permissions are added to the auth_permission database table when you run manage.py syncdb .

杩欎笁涓熀鏈潈闄愶細娣诲姞锛屽彉鏇村拰鍒犻櫎锛屼細琚嚜鍔ㄦ坊鍔犲埌鎵鏈夌殑Django妯″瀷涓紝鍙璇ユā鍨嬪寘鍚 class Admin 銆傚綋浣犳墽琛 manage.py syncdb 鐨勬椂鍊欙紝杩欎簺灏辫鑷姩娣诲姞鍒 auth_permission 鏁版嵁琛ㄤ腑銆

These permissions will be of the form "<app>.<action>_<object_name>" . That is, if you have a polls application with a Choice model, youll get permissions named "polls.add_choice" , "polls.change_choice" , and "polls.delete_choice" .

鏉冮檺浠 "<app>.<action>_<object_name>" 鐨勫舰寮忓嚭鐜般傚鏋滀綘鏈変竴涓 polls 鐨勫簲鐢紝鍖呭惈涓涓 Choice 妯″瀷锛屼綘灏辨湁浠ヤ笅涓変釜鏉冮檺锛屽垎鍒彨鍋 "polls.add_choice""polls.change_choice" 锛屽拰 "polls.delete_choice"

Note that if your model doesnt have class Admin set when you run syncdb , the permissions wont be created. If you initialize your database and add class Admin to models after the fact, youll need to run syncdb again to create any missing permissions for your installed applications.

娉ㄦ剰锛屽鏋滃綋浣犺繍琛 syncdb 鏃讹紝妯″瀷涓病鏈夊寘鍚 class Admin 锛岃妯″瀷瀵瑰簲鐨勬潈闄愬氨涓嶄細琚垱寤恒傚鏋滀綘鍦ㄥ垵濮嬪寲鏁版嵁搴撲互鍚庯紝鍙堝湪鑷繁鐨勬ā鍨嬩腑鍔犲叆浜 class Admin 锛屼綘灏遍渶瑕侀噸鏂拌繍琛 syncdb 鏉ヤ负搴旂敤鍔犲叆鏉冮檺銆

You can also create custom permissions for a given model object using the permissions attribute on Meta . This example model creates three custom permissions:

浣犱篃鍙互閫氳繃璁剧疆 Meta 涓殑 permissions 灞炴э紝鏉ヤ负缁欏畾鐨勬ā鍨嬪畾鍒舵潈闄愩備笅闈㈢殑渚嬪瓙鍒涘缓浜嗕笁涓嚜瀹氫箟鐨勬潈闄愶細

class USCitizen(models.Model):
    # ...
    class Meta:
        permissions = (
            # Permission identifier     human-readable permission name
            ("can_drive",               "Can drive"),
            ("can_vote",                "Can vote in elections"),
            ("can_drink",               "Can drink alcohol"),
        )

This only creates those extra permissions when you run syncdb ; its up to you to check for these permissions in your views.

褰撲綘杩愯 syncdb 鏃讹紝棰濆鐨勬潈闄愭墠浼氳鍔犲叆锛涗綘闇瑕佽嚜宸卞湪瑙嗗浘涓坊鍔犳潈闄愮浉鍏崇殑浠g爜銆

Just like users, permissions are implemented in a Django model that lives in django.contrib.auth.models . This means that you can use Djangos database API to interact directly with permissions if you like.

灏辫窡鐢ㄦ埛涓鏍凤紝鏉冮檺涔熷氨鏄疍jango妯″瀷涓殑 django.contrib.auth.models 銆傚洜姝ゅ鏋滀綘鎰挎剰锛屼綘涔熷彲浠ラ氳繃Django鐨勬暟鎹簱API鐩存帴鎿嶄綔鏉冮檺銆

Groups

Groups are a generic way of categorizing users so you can apply permissions, or some other label, to those users. A user can belong to any number of groups.

缁勬彁渚涗簡涓绉嶉氱敤鐨勬柟寮忔潵璁╀綘鎸夌収涓瀹氱殑鏉冮檺瑙勫垯鍜屽叾浠栨爣绛惧皢鐢ㄦ埛鍒嗙被銆備竴涓敤鎴峰彲浠ラ毝灞炰簬浠讳綍鏁伴噺鐨勭粍銆

A user in a group automatically has the permissions granted to that group. For example, if the group Site editors has the permission can_edit_home_page , any user in that group will have that permission.

鍦ㄤ竴涓粍涓殑鐢ㄦ埛鑷姩鑾峰緱浜嗚祴浜堣缁勭殑鏉冮檺銆備緥濡傦紝 Site editors 缁勬嫢鏈 can_edit_home_page 鏉冮檺锛屼换浣曞湪璇ョ粍涓殑鐢ㄦ埛閮芥嫢鏈夎繖涓潈闄愩

Groups are also a convenient way to categorize users to give them some label, or extended functionality. For example, you could create a group 'Special users' , and you could write code that could, say, give those users access to a members-only portion of your site, or send them members-only email messages.

缁勪篃鍙互閫氳繃缁欏畾涓浜涚敤鎴风壒娈婄殑鏍囪锛屾潵鎵╁睍鍔熻兘銆備緥濡傦紝浣犲垱寤轰簡涓涓 'Special users' 缁勶紝骞朵笖鍏佽缁勪腑鐨勭敤鎴疯闂珯鐐圭殑涓浜沄IP閮ㄥ垎锛屾垨鑰呭彂閫乂IP鐨勯偖浠舵秷鎭

Like users, the easiest way to manage groups is through the admin interface. However, groups are also just Django models that live in django.contrib.auth.models , so once again you can always use Djangos database APIs to deal with groups at a low level.

鍜岀敤鎴风鐞嗕竴鏍凤紝admin鎺ュ彛鏄鐞嗙粍鐨勬渶绠鍗曠殑鏂规硶銆傜劧鑰岋紝缁勪篃灏辨槸Django妯″瀷 django.contrib.auth.models 锛屽洜姝や綘鍙互浣跨敤Django鐨勬暟鎹簱API锛屽湪搴曞眰璁块棶杩欎簺缁勩

Messages

娑堟伅

The message system is a lightweight way to queue messages for given users. A message is associated with a User . Theres no concept of expiration or timestamps.

娑堟伅绯荤粺浼氫负缁欏畾鐨勭敤鎴锋帴鏀舵秷鎭傛瘡涓秷鎭兘鍜屼竴涓 User 鐩稿叧鑱斻傚叾涓病鏈夎秴鏃舵垨鑰呮椂闂存埑鐨勬蹇点

Messages are used by the Django admin interface after successful actions. For example, when you create an object, youll notice a The object was created successfully message at the top of the admin page.

鍦ㄦ瘡涓垚鍔熺殑鎿嶄綔浠ュ悗锛孌jango鐨刟dmin绠$悊鎺ュ彛灏变細浣跨敤娑堟伅鏈哄埗銆備緥濡傦紝褰撲綘鍒涘缓浜嗕竴涓璞★紝浣犱細鍦╝dmin椤甸潰鐨勯《涓婄湅鍒 The object was created successfully 鐨勬秷鎭

You can use the same API to queue and display messages in your own application. The API is simple:

浣犱篃鍙互浣跨敤鐩稿悓鐨凙PI鍦ㄤ綘鑷繁鐨勫簲鐢ㄤ腑鎺掗槦鎺ユ敹鍜屾樉绀烘秷鎭侫PI闈炲父鍦扮畝鍗曪細

  • To create a new message, use user.message_set.create(message='message_text') .

  • 瑕佸垱寤轰竴鏉℃柊鐨勬秷鎭紝浣跨敤 user.message_set.create(message='message_text')

  • To retrieve/delete messages, use user.get_and_delete_messages() , which returns a list of Message objects in the users queue (if any) and deletes the messages from the queue.

  • 瑕佽幏寰/鍒犻櫎娑堟伅锛屼娇鐢 user.get_and_delete_messages() 锛岃繖浼氳繑鍥炰竴涓 Message 瀵硅薄鐨勫垪琛紝骞朵笖浠庨槦鍒椾腑鍒犻櫎杩斿洖鐨勯」銆

In this example view, the system saves a message for the user after creating a playlist:

鍦ㄤ緥瀛愯鍥句腑锛岀郴缁熷湪鍒涘缓浜嗘挱鏀惧崟锛坧laylist锛変互鍚庯紝涓虹敤鎴蜂繚瀛樹簡涓鏉℃秷鎭

def create_playlist(request, songs):
    # Create the playlist with the given songs.
    # ...
    request.user.message_set.create(
        message="Your playlist was added successfully."
    )
    return render_to_response("playlists/create.html",
        context_instance=RequestContext(request))

When you use RequestContext , the current logged-in user and his or her messages are made available in the template context as the template variable {{ messages }} . Heres an example of template code that displays messages:

褰撲娇鐢 RequestContext 锛屽綋鍓嶇櫥褰曠殑鐢ㄦ埛浠ュ強浠栵紙濂癸級鐨勬秷鎭紝灏变細浠ユā鏉垮彉閲 {{ messages }} 鍑虹幇鍦ㄦā鏉跨殑context涓備笅闈㈡槸鏄剧ず娑堟伅鐨勪竴涓緥瀛愭ā鏉夸唬鐮侊細

{% if messages %}
<ul>
    {% for message in messages %}
    <li>{{ message }}</li>
    {% endfor %}
</ul>
{% endif %}

Note that RequestContext calls get_and_delete_messages behind the scenes, so any messages will be deleted even if you dont display them.

闇瑕佹敞鎰忕殑鏄 RequestContext 浼氬湪鍚庡彴璋冪敤 get_and_delete_messages 锛屽洜姝ゅ嵆浣夸綘娌℃湁鏄剧ず瀹冧滑锛屽畠浠篃浼氳鍒犻櫎鎺夈

Finally, note that this messages framework only works with users in the user database. To send messages to anonymous users, use the session framework directly.

鏈鍚庢敞鎰忥紝杩欎釜娑堟伅妗嗘灦鍙兘鏈嶅姟浜庡湪鐢ㄦ埛鏁版嵁搴撲腑瀛樺湪鐨勭敤鎴枫傚鏋滆鍚戝尶鍚嶇敤鎴峰彂閫佹秷鎭紝璇风洿鎺ヤ娇鐢ㄤ細璇濇鏋躲

Profiles

妗f

The final piece of the puzzle is the profile system. To understand what profiles are all about, lets first look at the problem.

鏈鍚庝竴涓毦棰樻槸妗f绯荤粺.涓轰簡鐞嗚В浠涔堟槸妗f,璁╂垜浠厛鐪嬬湅闂.

In a nutshell, many sites need to store more user information than is available on the standard User object. To compound the problem, most sites will have different extra fields. Thus, Django provides a lightweight way of defining a profile object thats linked to a given user. This profile object can differ from project to project, and it can even handle different profiles for different sites served from the same database.

绠鍗曟潵璇达紝璁稿缃戠珯闇瑕佸瓨鍌ㄦ瘮鏍囧噯 User 瀵硅薄鏇村鐨勭敤鎴蜂俊鎭備负浜嗚В鍐宠繖涓棶棰橈紝澶у鏁扮綉绔欓兘浼氭湁涓嶅悓鐨勯澶栧瓧娈点傛墍浠ワ紝Django鎻愪緵涓涓交閲忕骇鐨勬柟寮忓畾涔夋。妗堝璞¢摼鎺ュ埌鎸囧畾鐨勭敤鎴枫傝繖涓。妗堝璞″湪姣忎釜椤圭洰涓彲浠ユ槸涓嶅悓鐨勶紝鐢氳嚦鍙互涓哄悓涓鏁版嵁搴撴湇鍔$殑涓嶅悓鐨勭珯鐐瑰鐞嗕笉鍚岀殑妗f銆

The first step in creating a profile is to define a model that holds the profile information. The only requirement Django places on this model is that it have a unique ForeignKey to the User model; this field must be named user . Other that that, you can use any other fields you like. Heres a strictly arbitrary profile model:

鍒涘缓妗f鐨勭涓姝ユ槸瀹氫箟涓涓ā鍨嬶紙model锛夋潵瀛樺偍妗f淇℃伅銆侱jango瀵硅繖涓ā鍨嬫墍鍋氱殑鍞竴鐨勯檺鍒舵槸锛屽繀椤昏鍖呭惈鍞竴鐨勪竴涓 User 妯″瀷鐨 ForeignKey 锛岃屼笖杩欎釜瀛楁蹇呴』瑕佸彨鍋 user 銆傚叾浠栫殑瀛楁鍙互鐢变綘鑷繁鎺屾帶銆備笅闈㈡槸涓涓。妗堟ā鍨嬬殑渚嬪瓙锛

from django.db import models
from django.contrib.auth.models import User

class MySiteProfile(models.Model):
    # This is the only required field
    user = models.ForeignKey(User, unique=True)

    # The rest is completely up to you...
    favorite_band = models.CharField(maxlength=100, blank=True)
    favorite_cheese = models.CharField(maxlength=100, blank=True)
    lucky_number = models.IntegerField()

Next, youll need to tell Django where to look for this profile object. You do that by setting the AUTH_PROFILE_MODULE setting to the identifier for your model. So, if your model lives in an application called myapp , youd put this in your settings file:

涓嬩竴姝ワ紝浣犻渶瑕佸憡璇塂jango鍘诲摢閲屾煡鎵炬。妗堝璞°備綘鍙互閫氳繃璁剧疆妯″瀷涓殑 AUTH_PROFILE_MODULE 鍙橀噺杈惧埌杩欎釜鐩殑銆傚洜姝わ紝濡傛灉浣犵殑妯″瀷鍖呭惈鍦 myapp 杩欎釜搴旂敤涓紝浣犲氨闇瑕佸涓嬬紪鍐欎綘鐨勮缃枃浠讹細

AUTH_PROFILE_MODULE = "myapp.mysiteprofile"

Once thats done, you can access a users profile by calling user.get_profile() . This function could raise a SiteProfileNotAvailable exception if AUTH_PROFILE_MODULE isnt defined, or it could raise a DoesNotExist exception if the user doesnt have a profile already (youll usually catch that exception and create a new profile at that time).

涓鏃﹀畬鎴愶紝浣犲氨鍙互閫氳繃璋冪敤 user.get_profile() 鍑芥暟鏉ヨ幏寰楃敤鎴锋。妗堛傚鏋 AUTH_PROFILE_MODULE 鍙橀噺娌℃湁璁剧疆锛岃繖涓嚱鏁板彲鑳戒細鎶涘嚭 SiteProfileNotAvailable 寮傚父锛涘鏋滆繖涓敤鎴蜂笉瀛樺湪妗f锛屼篃鍙兘浼氭姏鍑 DoesNotExist 寮傚父锛堥氬父鎯呭喌涓嬶紝浣犱細鎹曡幏杩欎釜寮傚父骞跺湪褰撴椂鍒涘缓涓涓柊鐨勬。妗堬級銆

Whats Next

鎺ヤ笅鏉?

Yes, the session and authorization system is a lot to absorb. Most of the time you wont need all the features described in this chapter, but when you need to allow complex interactions between users, its good to have all that power available.

鏄殑锛屼細璇濆拰璁よ瘉绯荤粺鏈夊お澶氱殑涓滆タ瑕佸銆傚ぇ澶氭暟鎯呭喌涓嬶紝浣犲苟涓嶉渶瑕佹湰绔犳墍鎻愬埌鐨勬墍鏈夊姛鑳姐傜劧鑰屽綋浣犻渶瑕佸厑璁哥敤鎴蜂箣闂村鏉傜殑浜掓搷浣滄椂锛屾墍鏈夌殑鍔熻兘閮借兘浣跨敤灏辨樉寰楀緢閲嶈浜嗐

In the next chapter, well take a look at a piece of Django that builds on top of this session/user system: the comments application. It allows you to easily attach commentsfrom anonymous or authenticated usersto arbitrary objects. Onward and upward!

鍦ㄤ笅涓绔犺妭涓紝鎴戜滑浼氭潵娣卞叆浜嗚ВDjango寤虹珛鍦ㄤ細璇/鐢ㄦ埛绯荤粺涔嬩笂鐨勪竴涓郴缁燂細璇勮搴旂敤銆傚畠鍏佽浣犲緢鏂逛究鍦颁互鍖垮悕鐢ㄦ埛鎴栬呮敞鍐岀敤鎴风殑韬唤锛屽悜浠绘剰绫诲瀷鐨勫璞℃坊鍔犺瘎璁恒傝鎴戜滑缁х画鍚戝墠鍚с

Copyright 2006 Adrian Holovaty and Jacob Kaplan-Moss.
This work is licensed under the GNU Free Document License.
Hosting graciously provided by media temple
Chinese translate hosting by py3k.cn.