2015-07-08 8 views
7

मैं एक गनिकॉर्न सर्वर का उपयोग कर रहा हूं जिसमें मैं प्रति उपयोगकर्ता केवल एक सत्र को सीमित करने का तरीका समझने की कोशिश कर रहा हूं यानी यदि उपयोगकर्ता ए क्रोम से ऐप में लॉग इन है तो वह फ़ायरफ़ॉक्स के माध्यम से लॉगिन नहीं कर सकता है जब तक वह लॉग आउट नहीं करता क्रोम का, या क्रोम में एक और टैब खोलने में सक्षम नहीं होना चाहिए।फ्लास्क में उपयोगकर्ता नाम के लिए किसी भी ब्राउज़र से एक सत्र को सीमित कैसे करें?

मैं ब्राउज़र के लिए एक अद्वितीय आईडी कैसे बना सकता हूं और इसे डीबी में संग्रहीत कर सकता हूं ताकि उपयोगकर्ता लॉग आउट या सत्र समाप्त होने तक उपयोगकर्ता किसी अन्य ब्राउज़र से लॉगिन न कर सके।

उत्तर

7

एक टैब में सत्र सीमित करने की एक संभावित विधि में पृष्ठ लोड पर एक यादृच्छिक टोकन बनाना और पृष्ठ में इस टोकन को एम्बेड करना शामिल है। यह हाल ही में जेनरेट किया गया टोकन उपयोगकर्ता के सत्र में भी संग्रहीत हो जाता है। यह CSFR हमलों को रोकने के लिए सत्यापन फ्रेम टोकन को जोड़ने के समान होगा।

संक्षिप्त उदाहरण: फ़ायरफ़ॉक्स में टैब 1 में

  • उपयोगकर्ता भार पेज। Token1 सत्र
  • उपयोगकर्ता में फ़ायरफ़ॉक्स में टैब 2 में पृष्ठ लोड किया गया है, एम्बेडेड और संग्रहीत किया गया है। Token2 सत्र में एम्बेडेड, एम्बेडेड और संग्रहीत है। यह पिछले मान को ओवरराइट करता है।
  • उपयोगकर्ता क्रोम में टैब 1 में पृष्ठ लोड करता है। Token3 सत्र में एम्बेडेड और एम्बेडेड होता है। यह पिछले मान को ओवरराइट करता है।

इस बिंदु पर, उपयोगकर्ता को 3 टैब में पृष्ठ खुलता है। उपयोगकर्ता का सत्र, हालांकि, केवल Token3 संग्रहीत है। यह विधि उपयोगकर्ता को लॉक होने से रोकती है (विभिन्न आईपी पते, अलग-अलग उपयोगकर्ता एजेंट स्ट्रिंग्स, इंकोगनेटो मोड इत्यादि) क्योंकि प्रत्येक नया सत्र बस एक नया टोकन उत्पन्न करता है। नवीनतम लोड सक्रिय विंडो बन जाता है, जो तुरंत पिछले सभी सत्रों को अमान्य कर देता है।

अगला, पृष्ठ किसी भी समय सर्वर के साथ इंटरैक्ट करता है (एक लिंक पर क्लिक करता है, डेटा सबमिट करता है), पृष्ठ में एम्बेडेड टोकन भी भेजा जाता है। सर्वर मान्य करता है कि पास टोकन सत्र में टोकन से मेल खाता है। यदि वे मेल खाते हैं, तो कार्रवाई सफल होती है। यदि वे मेल नहीं खाते हैं, तो सर्वर विफलता संदेश देता है।


आप कई तरीकों से यादृच्छिक संख्याएं उत्पन्न कर सकते हैं, लेकिन आप शायद कुछ सुरक्षित चाहते हैं।हम एक और सवाल से example का उपयोग करेंगे:

import string 
import random 
... 
N = 20 # Length of the string we want, adjust as appropriate 
''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(N)) 

यह random.SystemRandom का उपयोग करता है, जो केवल random.choice


का उपयोग कर पृष्ठ लोड पर से ज्यादा सुरक्षित है, तो आप मौजूदा टोकन मान्य है जांच करने की आवश्यकता , यादृच्छिक टोकन उत्पन्न करें और इसे उपयोगकर्ता के सत्र में संग्रहीत करें। चूंकि हम इसे हर जगह चाहते हैं, चलिए बाद में डुप्लिकेट कोड को कम करने के लिए एक सजावटी बनाते हैं। सजावट जांचता है कि क्या सत्र मान्य है और यदि आपको यह नहीं चुनना है कि क्या करना है (अपना तर्क डालें)। यह एक सत्र टोकन भी सेट करता है। इसकी आवश्यकता है (या आपको अपने मुख्य पृष्ठ को बाहर करने के लिए तर्क की आवश्यकता है) अन्यथा आप एक अनंत लूप दबाएंगे जहां उपयोगकर्ता मुख्य पृष्ठ लोड करने का प्रयास करता है, इसमें कोई टोकन नहीं है, विफल रहता है और प्रक्रिया दोहराती है। मेरे पास else खंड के माध्यम से प्रत्येक पृष्ठ लोड पर पुनर्जन्म टोकन है। यदि आप if अनुभाग को लागू नहीं करते हैं, तो यह सजावटी व्यर्थ है क्योंकि दोनों पथ एक ही क्रिया करते हैं और पृष्ठ लोड पर टोकन को रीसेट करते हैं। if में तर्क यह है कि उपयोगकर्ता को कई सत्र होने से रोका जाएगा।

from flask import session 
from functools import wraps 

def random_string(length): 
    return ''.join(random.SystemRandom().choice(string.ascii_uppercase + string.digits) for _ in range(length)) 

def validate_token(f): 
    @wraps(f) 
    def wrapper(existing_token, *args, **kwargs): 
     if session['token'] != existing_token: 
      # Logic on failure. Do you present a 404, do you bounce them back to your main page, do you do something else? 
      # It is IMPORTANT that you determine and implement this logic 
      # otherwise the decorator simply changes the token (and behaves the same way as the else block). 
      session['token'] = random_string(20) 
     else: 
      session['token'] = random_string(20) 
     return f(*args, **kwargs) 
    return wrapper 

अब हमारे मार्गों में, हम इस डेकोरेटर प्रत्येक है, ताकि उपयोगकर्ता सत्र प्रत्येक पृष्ठ लोड पर अद्यतन किया जाता आवेदन कर सकते हैं:

from flask import render_template 

@app.route('/path') 
@validate_token 
def path(token=None): 
    return render_template('path.html', token=session['token']) 

अपने टेम्पलेट में, आप इस token मूल्य का उपयोग करना चाहते हैं कहीं भी आपको सत्र को जारी रखने से रोकने की आवश्यकता है। उदाहरण के लिए, इसे लिंक पर रखें, रूपों में (हालांकि Flask has a method of CSRF protection पहले से ही), आदि सर्वर स्वयं जांच सकता है कि पास टोकन मान्य है या नहीं। टेम्पलेट इस तरह के रूप में सरल दिख सकता है:

<a href="{{ url_for('path', token=token) }}">Click here to continue</a> 
2

मैं कैसे वास्तव में इसे लागू करने के पता नहीं है, लेकिन ऐसा लगता है कि आप की आवश्यकता websockets (here देखें)

इस तरह, हर पृष्ठ लोड पर, आप सर्वर पर एक Ajax अनुरोध हो सकता था, जो होगा पहले खोले गए ब्राउज़र + टैब, यदि कोई हो, तो क्वेरी करने के लिए websocket कार्यक्षमता का उपयोग करें। यदि इसका उत्तर है, तो इसका मतलब है कि एक और ब्राउज़र + टैब खुला है। सर्वर को तब यह जानकारी वापस करनी चाहिए।

आपकी स्क्रिप्ट जिसे रिटर्न के आधार पर अजाक्स के माध्यम से सर्वर कहा जाता है, उसके बाद किसी त्रुटि पृष्ठ पर रीडायरेक्ट करने का निर्णय लेना चाहिए, या इसे लोड करना जारी रखना चाहिए।

मैंने कभी भी वेबसाइट का उपयोग नहीं किया, लेकिन मुझे पूरा भरोसा है कि यह काम करेगा (जैसा कि is well implemented in most browsers now है)।

+0

क्या आप कैशिंग का उपयोग करके ऐसा करने के किसी भी तरीके से जानते हैं? – user2601010

+0

नहीं ... मैंने कभी भी वास्तविक परियोजना में फ्लास्क का उपयोग नहीं किया है, मैं एक Django उपयोगकर्ता से अधिक हूं। कहा जा रहा है, मैं वास्तव में नहीं देखता क्यों कैशिंग एक समस्या होगी, – BriceP

संबंधित मुद्दे