Matt समझाया गया है, यह केवल संदर्भ का मामला है। उनके स्पष्टीकरण के लिए धन्यवाद, मैं यूनिट परीक्षणों के दौरान पहचान स्विच करने के दो अलग-अलग तरीकों से आया था।
सब से पहले, के एक सा आवेदन निर्माण संशोधित:
def _on_principal_init(sender, identity):
"Sets the roles for the 'admin' and 'member' identities"
if identity.id:
if identity.id == 'admin':
identity.provides.add(RoleNeed('admin'))
identity.provides.add(RoleNeed('member'))
def create_app():
app = flask.Flask(__name__)
app.debug = True
app.config.update(SECRET_KEY='secret',
TESTING=True)
principal = Principal(app)
identity_loaded.connect(_on_principal_init)
#
@app.route('/')
def index():
return "OK"
#
@app.route('/member')
@roles_accepted('admin', 'member')
def role_needed():
return "OK"
#
@app.route('/admin')
@roles_required('admin')
def connect_admin():
return "OK"
# Using `flask.ext.principal` `Permission.require`...
# ... instead of Matt's decorators
@app.route('/admin_alt')
@admin_permission.require()
def connect_admin_alt():
return "OK"
return app
एक पहली संभावना एक समारोह है कि हमारे परीक्षण में प्रत्येक अनुरोध से पहले एक पहचान लोड करता है बनाने के लिए है। सबसे आसान टेस्ट स्वीट के setUpClass
में यह घोषणा करने के लिए के बाद एप्लिकेशन बनाया जाता है, app.before_request
डेकोरेटर का उपयोग कर रहा है:
class WorkshopTestOne(unittest.TestCase):
#
@classmethod
def setUpClass(cls):
app = create_app()
cls.app = app
cls.client = app.test_client()
@app.before_request
def get_identity():
idname = flask.request.args.get('idname', '') or None
print "Notifying that we're using '%s'" % idname
identity_changed.send(current_app._get_current_object(),
identity=Identity(idname))
फिर, परीक्षण बन:
def test_admin(self):
r = self.client.get('/admin')
self.assertEqual(r.status_code, 403)
#
r = self.client.get('/admin', query_string={'idname': "member"})
self.assertEqual(r.status_code, 403)
#
r = self.client.get('/admin', query_string={'idname': "admin"})
self.assertEqual(r.status_code, 200)
self.assertEqual(r.data, "OK")
#
def test_admin_alt(self):
try:
r = self.client.get('/admin_alt')
except flask.ext.principal.PermissionDenied:
pass
#
try:
r = self.client.get('/admin_alt', query_string={'idname': "member"})
except flask.ext.principal.PermissionDenied:
pass
#
try:
r = self.client.get('/admin_alt', query_string={'idname': "admin"})
except flask.ext.principal.PermissionDenied:
raise
self.assertEqual(r.data, "OK")
(संयोग से, बहुत पिछले परीक्षण से पता चलता है कि मैट डेकोरेटर दूर का उपयोग करना आसान कर रहे हैं ....)
एक दूसरा दृष्टिकोण एकसाथ test_request_context
फ़ंक्शन का उपयोग करता एक अस्थायी संदर्भ बनाने के लिए।एक समारोह @app.before_request
से सजाया परिभाषित करने के लिए कोई ज़रूरत नहीं, बस मार्ग test_request_context
के तर्क के रूप में परीक्षण करने के लिए पारित, मैट की प्रतिक्रिया ही संदर्भ में identity_changed
संकेत
class WorkshopTestTwo(unittest.TestCase):
#
@classmethod
def setUpClass(cls):
app = create_app()
cls.app = app
cls.client = app.test_client()
cls.testing = app.test_request_context
def test_admin(self):
with self.testing("/admin") as c:
r = c.app.full_dispatch_request()
self.assertEqual(r.status_code, 403)
#
with self.testing("/admin") as c:
identity_changed.send(c.app, identity=Identity("member"))
r = c.app.full_dispatch_request()
self.assertEqual(r.status_code, 403)
#
with self.testing("/admin") as c:
identity_changed.send(c.app, identity=Identity("admin"))
r = c.app.full_dispatch_request()
self.assertEqual(r.status_code, 200)
self.assertEqual(r.data, "OK")
मैं क्या डर था है कि: मैं संदर्भों में खो रहा हूँ। AFAIU, उसी संदर्भ का उपयोग करके, अनुरोध पर संसाधित होने से पहले आपकी 'निर्धारित_ पहचान' कहा जाएगा, है ना? इसलिए, मुझे उस संदर्भ में कहीं भी एक पहचान घोषित करने की आवश्यकता है, या इसे कुछ वैश्विक संदर्भ से पुनर्प्राप्त करना है, या अनुरोध पर पारित कुछ अतिरिक्त तर्कों से फ्लाई पर इसे बनाना है (उदाहरण के लिए, 'query_string') ... मैं कोशिश करूंगा किसी अन्य उत्तर में कुछ समाधान पोस्ट करने के लिए, यदि आप मुझे बताएंगे कि आपने क्या सोचा था तो मैं बहुत आभारी हूं। –
सही। लेकिन मुझे यकीन नहीं है कि आप इससे क्यों डरते हैं। और हां, 'request_identity' फ़ंक्शन प्रत्येक अनुरोध पर कॉल किया जाएगा और आपके संदर्भ विधियों के साथ समान संदर्भ साझा करेगा। पहचान निर्धारित करना इस बात पर निर्भर करता है कि आप उपयोगकर्ताओं को प्रमाणीकृत करने की योजना कैसे बनाते हैं। उदाहरण के लिए, यदि आप सत्र आधारित प्रमाणीकरण तंत्र चाहते हैं तो आपको फ्लास्क-प्रिंसिपल को फ्लास्क-लॉगिन के साथ जोड़ना चाहिए। यदि आप एक एपीआई बना रहे हैं जो स्टेटलेस है, तो आपको हेडर में ऑथ पैरामीटर पास करना चाहिए या मूल http auth का उपयोग करना चाहिए और उस मान से 'defin_identity' में उपयोगकर्ता को निर्धारित करना चाहिए। –
एक बात जो मैं उल्लेख करने में असफल रहा वह यह है कि डिफ़ॉल्ट रूप से फ्लास्क-प्रिंसिपल, सत्र में पहचान सहेजता है, इसलिए पहली बार जब आप 'identity_changed.send' विधि को कॉल करते हैं तो यह सत्र में पहचान संग्रहीत करेगा और प्रत्येक अनुरोध के लिए इसे लोड करेगा स्थिर अंतराल को छोड़कर। –