chapter 9 - 用戶角色
角色管理,可以參考 QQ群裡面的不同角色身份來理解,QQ群裡面有群主、管理員、普通成員這三個身份(其實還有個「遊客」的身份);如果有使用過論壇模塊建站的也可以知道, 論壇裡面的用戶也是有幾個不同的角色屬性的。而這個身份屬性的實現,在本書中,是依靠用戶資料庫表裡面的屬性來確定的。
9.1 角色在資料庫中的表示
app/models.py 角色的許可權
class Role(db.Model): __tablename__ = roles id = db.Column(db.Integer, primary_key = True) name = db.Column(db.String(64), unique = True) default = db.Column(db.Boolean, default = False, index = True) permissions = db.Column(db.Integer) users = db.relationship(User, backred = role, lazy = dynamic)
代碼增加了2個欄位:default和permissions,分別用於默認角色和許可權的設置。permissions的值是一個整數,表示位值,它是一個用位表示的許可權值。本程序中所設置的許可權有:
操作位值說明關注用戶0b00000001 (0x01)關注其他用戶在他人的文章中發表評論0b00000010 (0x02)在他人撰寫的文章中發布評論寫文章0b00000100 (0x04)寫原創文章管理他人發表的評論0b00001000 (0x08)查處他人發表的不當評論管理員許可權0b10000000 (0x80)管理網站
以上許可權用代碼表示為:
app/models.py
class Permission: FOLLOW = 0x01 COMMENT = 0x02 WRITE_ARTICLES = 0x04 MODERATE_COMMENTS = 0x08 ADMINISTRATER = 0x80
下表是程序所支持的用戶角色及其使用到的許可權位:
用戶角色許可權說明匿名0b00000000 (0x00)未登錄的用戶。在程序中只有閱讀許可權用戶0b00000111 (0x07)具有發布文章、發表評論和關注其他用戶的許可權。這是新用戶的默認角色協管員0b00001111 (0x0f)增加審查不當評論的許可權管理員0b11111111 (0xff)具有所有許可權,包括修改其他用戶所屬角色的許可權在Role類中把角色手動添加到資料庫中:
app/models.py
class Role(db.Model): # 之前的代碼 @staticmethod def insert_roles(): roles = { User: (Permission.FOLLOW | Permission.COMMENT | Permission.WRITE_ARTICLES, True), Moderator: (Permission.FOLLOW | Permission.COMMENT | Permission.WRITE_ARTICLES | Permission.MODERATE_COMMENTS, False), Administrator: (0xff, False) } for r in roles: role = Role.query.filter_by(name=r).first() if role is None: role = Role(name=r) role.permissions = roles[r][0] role.default = roles[r][1] db.session.add(role) db.session.commit()
以上代碼設置了3種不同的用戶角色以及它們的默認值,並判斷在當前的資料庫表中是否已存在這樣的角色,如果沒有則新增,在新增的同時會設置角色的默 認值和許可權。「匿名」角色(個人理解也就是第8章最後提到的未激活的用戶)在這裡並沒有表示出來,因為「匿名」即表示著其不存在於資料庫中。 要把以上代碼中設置的幾種角色寫入到資料庫中,需要在shell中進行如下操作:
(venv) $ python manage.py shell>>> Role.insert_roles()>>> Role.query.all()[<Role uAdministrator>, <Role uUser>, <Role uModerator>]
我個人學習到這裡的,按照上面的代碼執行操作時,出現了錯誤,提示role.default欄位不存在。多次嘗試也沒有解決。最終是直接把本書git倉庫中9a裡面的資料庫文件拿來替換了,才可以正常進行。
9.2 賦予角色
用戶在註冊時,即要給其賦予相應的角色。一般都是普通用戶的角色,也就是User,因為它是默認角色。唯一例外的是管理員,管理員由保存在系統變數FLASKY_ADMIN中的電子郵件地址識別,只要這個地址被用於註冊了,那它就會被賦予管理員的角色。
app/models.py 定義默認用戶角色
# 要先從flask_login引入UserMixin,這個作者似乎在接下來的一節才說到class User(UserMixin, db.Model): # 之前的代碼 def __init__(self, **kwargs): super(User, self).__init__(**kwargs) if self.role is None: if self.email == curent_app.config[FLASKY_ADMIN]: self.role = Role.query.filter_by(permissions=0xff).first() if self.role is None: self.role = Role.query.filter_by(default=True).first() # 後面的代碼
9.3 角色驗證
角色驗證,就是檢查某個用戶是否具有指定的許可權。在用戶表User中實現
app/models.py 檢查用戶是否有指定的許可權
from flask_login import UserMixin, AnonymousUserMixinclass User(UserMixin, db.Model): # 之前的代碼 def can(self, permissions): return self.role is not None and (self.role.permissions & permissions) == permissions def is_administratro(self): return self.can(Permission.ADMINISTER)class AnonymousUser(AnonymousUserMixin): def can(self, permissions): return False def is_administrator(self): return Falselogin_manager.anonymous_user = AnonymousUser
User中添加的can()方法在請求許可權和其原有的(被程序賦予的)許可權之間進行位與操作,其實這就是把所請求的許可權和用戶所擁有的許可權進行了匹配,如果完全匹配,則返回True。檢查管理員許可權的方法被單獨了出來,因為其經常被用到。
AnonymousUser類是用於檢查匿名用戶許可權的
在模板中也需要進行許可權檢查,為了方便起見,需要把在app/models.py中定義的`Permission`類加入到上下文中(這個一時理解不了) app/main/___init___.py
# 這裡需要先從..models導入Permission 書中又沒有提到@main.app_context_processordef inject_permissions(): return dict(Permission=Permission)
用戶角色和許可權的單元測試
test/test_user_model.py
class UserModelTestCase(unittest.TestCase): # 之前的代碼 def test_roles_and_permissions(self): Role.insert_roles() u = User(email=john@example.com, password=cat) self.assertTrue(u.can(Permission.WRITE_ARTICLES)) self.assertFalse(u.can(Permission.MODERATE_COMMENTS)) def test_anonymous_user(self): u = AnonymousUser() self.assertFalse(u.can(Permission.FOLLOW))
由於在前面的章節中曾有創建角色,但那時並未創建許可權,因此,在此需要對資料庫進行更新,為那些在本章之前創建的用戶添加用戶角色。
又因為在上一章的最後,為了完善程序的幾個功能,作者已經進一步地完善了代碼,但是並沒有在書中出現,所以在這裡最好要參考本書在github中的程序代碼進行修改,或者直接checkout 9a倉庫
(像專欄簡介裡面寫的那樣,這專欄本來就是寫來讓我自己加深記憶和以後再學習的時候可以避開一些坑的,並沒有想過會有人關注。但目前還是有知友關注了,為了避免誤導看到的朋友,我想提醒下各位,記得要自己去甄別我的文章中的內容,有對的也可能會有錯誤的,我也希望有人能提出。當然我自己也希望能夠完全理解書中的內容,然後再寫筆記。但還是會有時候一時理解不了只能先跳過,不然就一直卡在那裡了。這第9章中,就有這樣的情況)
推薦閱讀:
※希望用flask作為中介讓python和js交互,大家有什麼比較好的實踐經驗沒?
※Flask實踐:計算器
※Flask項目配置(Configuration)
※flask框架中應用上下文跟請求上下文是什麼意思?
※上雲連載4:資料庫備份與恢復