জ্যাঙ্গোর লগইন তৈরির সর্বোত্তম উপায়_প্রয়োজনটি পূর্বনির্ধারিত


103

আমি একটি বিশাল জ্যাঙ্গো অ্যাপে কাজ করছি, যার বেশিরভাগ অংশের অ্যাক্সেসের জন্য লগইন প্রয়োজন। এর অর্থ এই যে আমাদের সমস্ত অ্যাপ্লিকেশন জুড়ে আমরা ছিটিয়েছি:

@login_required
def view(...):

এটি দুর্দান্ত, এবং যতক্ষণ না আমরা এটিকে সর্বত্র যুক্ত করার কথা মনে করি ততক্ষণ তা দুর্দান্ত কাজ করে ! দুঃখের বিষয় মাঝে মাঝে আমরা ভুলে যাই, এবং ব্যর্থতা প্রায়শই ভয়াবহভাবে স্পষ্ট হয় না। যদি কোনও দৃশ্যের একমাত্র লিঙ্কটি @ লগিন_ প্রয়োজনীয় পৃষ্ঠায় থাকে তবে আপনি সম্ভবত লক্ষ্য করবেন না যে আপনি লগ ইন না করেই এই দৃশ্যে পৌঁছাতে পারবেন But তবে খারাপ লোকেরা লক্ষ্য করতে পারে যা একটি সমস্যা।

আমার ধারণা ছিল সিস্টেমটি বিপরীত করা। সর্বত্র @ লগিন_প্রযুক্তি টাইপ না করে বরং এর মতো আমার কিছু হবে:

@public
def public_view(...):

শুধু পাবলিক স্টাফ জন্য। আমি কিছু মিডলওয়্যার দিয়ে এটি বাস্তবায়নের চেষ্টা করেছি এবং এটি কাজ করে বলে মনে হচ্ছে না। আমি যে সকল মিডলওয়্যার ব্যবহার করছি তার সাথে আমি খারাপ ব্যবহার করার চেষ্টা করেছি বলে মনে করি। এরপরে ইউআরএল নিদর্শনগুলি অতিক্রম করার জন্য আমি কিছু লেখার চেষ্টা করেছিলাম তা পরীক্ষা করে দেখুন যে @ প্রজাতন্ত্র নয় এমন সমস্ত কিছুই @ লগিন_প্রযুক্তি চিহ্নিত হয়েছে - কমপক্ষে যদি আমরা কিছু ভুলে যাই তবে আমরা দ্রুত ত্রুটি পেতে চাই। তবে আমি কীভাবে জানাতে পারি না যে @ লগিন_প্রয়োজনীয় কোনও দৃশ্যে প্রয়োগ করা হয়েছে কিনা ...

সুতরাং, এটি করার সঠিক উপায় কী? সাহায্যের জন্য ধন্যবাদ!


2
দুর্দান্ত প্রশ্ন। আমি ঠিক একই অবস্থানে ছিলাম। পুরো সাইটটি লগইন_প্রযুক্তি তৈরির জন্য আমাদের কাছে মিডলওয়্যার রয়েছে এবং বিভিন্ন লোক / ভূমিকার জন্য বিভিন্ন ভিউ / টেমপ্লেট-টুকরোগুলি দেখানোর জন্য আমাদের কাছে বাড়ির বর্ধিত এসিএল রয়েছে, তবে এটি উভয়টির থেকে আলাদা।
পিটার রওয়েল

উত্তর:


99

মিডলওয়্যার আপনার সেরা বাজি হতে পারে। আমি অতীতে এই কোডের টুকরোটি ব্যবহার করেছি, অন্য কোথাও পাওয়া স্নিপেট থেকে সংশোধিত:

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):
    """
    Middleware component that wraps the login_required decorator around
    matching URL patterns. To use, add the class to MIDDLEWARE_CLASSES and
    define LOGIN_REQUIRED_URLS and LOGIN_REQUIRED_URLS_EXCEPTIONS in your
    settings.py. For example:
    ------
    LOGIN_REQUIRED_URLS = (
        r'/topsecret/(.*)$',
    )
    LOGIN_REQUIRED_URLS_EXCEPTIONS = (
        r'/topsecret/login(.*)$',
        r'/topsecret/logout(.*)$',
    )
    ------
    LOGIN_REQUIRED_URLS is where you define URL patterns; each pattern must
    be a valid regex.

    LOGIN_REQUIRED_URLS_EXCEPTIONS is, conversely, where you explicitly
    define any exceptions (like login and logout URLs).
    """
    def __init__(self):
        self.required = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url) for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def process_view(self, request, view_func, view_args, view_kwargs):
        # No need to process URLs if user already logged in
        if request.user.is_authenticated():
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

তারপরে সেটিংস.পাইতে, আপনি যে বেস URL টি সুরক্ষিত করতে চান তা তালিকাবদ্ধ করুন:

LOGIN_REQUIRED_URLS = (
    r'/private_stuff/(.*)$',
    r'/login_required/(.*)$',
)

আপনার সাইট যতক্ষণ না প্রমাণীকরণের জন্য প্রয়োজনীয় পৃষ্ঠাগুলির জন্য ইউআরএল কনভেনশন অনুসরণ করে, এই মডেলটি কাজ করবে। যদি এটি ওয়ান-টু ওয়ান ফিট না হয় তবে আপনি আপনার পরিস্থিতিতে আরও ঘনিষ্ঠভাবে অনুসারে মিডওয়্যারটি পরিবর্তন করতে বেছে নিতে পারেন।

আমি এই পদ্ধতির বিষয়ে যা পছন্দ করি - সজ্জকারগণের সাথে কোডবেস লিটারের প্রয়োজনীয়তা অপসারণের পাশাপাশি @login_required- যদি প্রমাণীকরণের স্কিমটি পরিবর্তন হয় তবে আপনি বিশ্বব্যাপী পরিবর্তন করতে যেতে পারেন।


ধন্যবাদ, এটি দুর্দান্ত দেখাচ্ছে! আমার মিডওয়্যারটিতে লগইন_প্রযুক্তি () ব্যবহার করার বিষয়টি আমার কাছে ঘটেনি। আমার মনে হয় এটি আমাদের মিডলওয়্যার স্ট্যাকের সাথে যে সমস্যাটি খেলছিল তা ভাল করতে সহায়তা করবে।
সাম্তেগর

ডোহ! এটি প্রায় হুবহু প্যাটার্ন আমরা পৃষ্ঠাগুলি একদল জন্য ব্যবহার করা হয় ছিল HTTPS দ্বারা হতে, এবং অন্য সব কিছুর উচিত না HTTPS দ্বারা হও। এটি 2.5 বছর আগে ছিল এবং আমি এটি সম্পর্কে সম্পূর্ণরূপে ভুলে গিয়েছিলাম। থ্যাঙ্কস, ড্যানিয়েল!
পিটার রোয়েল

4
মিডলওয়্যারের প্রয়োজনীয়তা লগিনমিডলওয়ার ক্লাসটি কোথায় রাখা উচিত? ভিউ.পি, মডেল.পি?
ইয়াসিন

1
@richard সাজসজ্জাগুলি সংকলনের সময়ে চালিত হয়, এবং এই ক্ষেত্রে আমি যা করেছি তা হ'ল: ফাংশন.পাবলিক = সত্য। তারপরে মিডলওয়্যারটি চললে এটি অ্যাক্সেসের অনুমতি দেয় কি না তা ঠিক করার জন্য ফাংশনটিতে গণতান্ত্রিক পতাকাটি সন্ধান করতে পারে। যদি তা বোঝা না যায় তবে আমি আপনাকে পুরো কোডটি পাঠাতে পারি।
সাম্তেগর

1
আমি মনে করি @publicসজ্জা তৈরির পক্ষে সর্বোত্তম পন্থা , যা _publicদৃশ্যে অ্যাট্রিবিউট সেট করে এবং মিডলওয়্যারগুলি সেই দর্শনগুলি এড়িয়ে যায়। জ্যাঙ্গোর সিএসআরএফ_মুক্তি সাজসজ্জারক একইভাবে কাজ করে
ইভান ভাইরাবায়ান

31

প্রতিটি ভিউ ফাংশনে ডেকরেটার লাগানোর বিকল্প রয়েছে। আপনি ফাইলটিতে login_required()ডেকরেটারও রাখতে পারেন urls.py। যদিও এটি এখনও একটি ম্যানুয়াল কাজ, কমপক্ষে আপনার কাছে এটি এক জায়গায় রয়েছে যা নিরীক্ষণ করা সহজ করে।

যেমন,

    আমার_দর্শনগুলি হোম_ভিউ থেকে আমদানি করে

    urlpatterns = নিদর্শন ('',
        # "বাড়ি":
        (আর '^ $', লগইন_প্রয়োজনীয় (হোম_ভিউ), ডিক্ট (টেমপ্লেট_নাম = 'মাই_সাইট / হোম এইচটিএমএল', আইটেম_পার_ পৃষ্ঠা = 20)),
    )

নোট করুন যে দেখুন ফাংশনগুলি নাম হিসাবে চিহ্নিত করা হয় এবং সরাসরি আমদানি করা হয়, স্ট্রিং হিসাবে নয়।

এছাড়াও লক্ষ করুন যে এটি ক্লাস সহ যে কোনও কলযোগ্য ভিউ অবজেক্টের সাথে কাজ করে।


3

জাজাঙ্গো ২.১ এ আমরা একটি ক্লাসে সমস্ত পদ্ধতি সাজাতে পারি :

from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from django.views.generic import TemplateView

@method_decorator(login_required, name='dispatch')
class ProtectedView(TemplateView):
    template_name = 'secret.html'

আপডেট: আমি নিম্নলিখিতগুলিও কাজ করতে পেয়েছি:

from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView

class ProtectedView(LoginRequiredMixin, TemplateView):
    template_name = 'secret.html'

এবং LOGIN_URL = '/accounts/login/'আপনার সেটিংসে সেট করুন


1
এই নতুন উত্তরের জন্য ধন্যবাদ। তবে দয়া করে এটি সম্পর্কে লিল বিটটি ব্যাখ্যা করুন, আমি অফিসিয়াল ডকটি পড়লেও তা পেতে পারি না। ইয়া আগাম সহায়তার জন্য ধন্যবাদ
তিয়ান লুন

@ টিয়ানলুন দয়া করে আমার আপডেট হওয়া উত্তরটি দেখুন, এটি সাহায্য করতে পারে।
andyandy

2

ইউআরএলগুলি ফাংশন দেখার জন্য যেভাবে দেওয়া হয়েছে তা পুনরায় কাজ না করেই জাঙ্গোর অন্তর্নির্মিত অনুমানগুলি পরিবর্তন করা শক্ত।

জ্যাঙ্গো ইন্টার্নালগুলিতে মাতামাতি করার পরিবর্তে, আপনি ব্যবহার করতে পারেন এমন একটি নিরীক্ষা এখানে। কেবল প্রতিটি দর্শন ফাংশন পরীক্ষা করুন।

import os
import re

def view_modules( root ):
    for path, dirs, files in os.walk( root ):
        for d in dirs[:]:
            if d.startswith("."):
                dirs.remove(d)
        for f in files:
            name, ext = os.path.splitext(f)
            if ext == ".py":
                if name == "views":
                    yield os.path.join( path, f )

def def_lines( root ):
    def_pat= re.compile( "\n(\S.*)\n+(^def\s+.*:$)", re.MULTILINE )
    for v in view_modules( root ):
        with open(v,"r") as source:
            text= source.read()
            for p in def_pat.findall( text ):
                yield p

def report( root ):
    for decorator, definition in def_lines( root ):
        print decorator, definition

এটি চালান এবং defউপযুক্ত সজ্জকার ছাড়াই ফলাফল নির্ধারণ করুন ।


2

জাঙ্গো ১.১০+ এর জন্য এখানে একটি মিডলওয়্যার সমাধান রয়েছে

মিডলওয়্যারগুলি জঙ্গো 1.10+ তে নতুনভাবে লিখতে হবে

কোড

import re

from django.conf import settings
from django.contrib.auth.decorators import login_required


class RequireLoginMiddleware(object):

    def __init__(self, get_response):
         # One-time configuration and initialization.
        self.get_response = get_response

        self.required = tuple(re.compile(url)
                              for url in settings.LOGIN_REQUIRED_URLS)
        self.exceptions = tuple(re.compile(url)
                                for url in settings.LOGIN_REQUIRED_URLS_EXCEPTIONS)

    def __call__(self, request):

        response = self.get_response(request)
        return response

    def process_view(self, request, view_func, view_args, view_kwargs):

        # No need to process URLs if user already logged in
        if request.user.is_authenticated:
            return None

        # An exception match should immediately return None
        for url in self.exceptions:
            if url.match(request.path):
                return None

        # Requests matching a restricted URL pattern are returned
        # wrapped with the login_required decorator
        for url in self.required:
            if url.match(request.path):
                return login_required(view_func)(request, *view_args, **view_kwargs)

        # Explicitly return None for all non-matching requests
        return None

স্থাপন

  1. আপনার প্রকল্প ফোল্ডারে কোডটি অনুলিপি করুন এবং মিডলওয়্যার.পি হিসাবে সংরক্ষণ করুন
  2. মিডলওয়ারে যুক্ত করুন

    মিডলওয়্যার = [... '.মিডলওয়্যার.উইকায়ারলগিনমিডলওয়্যার', # লগইন প্রয়োজন]

  3. আপনার সেটিংসে যুক্ত করুন।
LOGIN_REQUIRED_URLS = (
    r'(.*)',
)
LOGIN_REQUIRED_URLS_EXCEPTIONS = (
    r'/admin(.*)$',
)
LOGIN_URL = '/admin'

সূত্র:

  1. ড্যানিয়েল নাবের এই উত্তর

  2. জ্যাঙ্গো মিডলওয়্যার টিউটোরিয়াল ম্যাক্স গুডরিজ

  3. জ্যাঙ্গো মিডলওয়্যার ডক্স


মনে রাখবেন যে কিছু না হলেও __call__, process_view
হুকটি

1

বারের উত্তরে অনুপ্রাণিত হয়ে আমি একটি সামান্য স্নিপেট লিখেছি যা patternsফাংশনটির পরিবর্তে , ইউআরএল সমস্ত কলব্যাকগুলি ডেকরেটারের সাথে আবৃত করে login_required। এটি জাজানো ১.6 এ কাজ করে।

def login_required_patterns(*args, **kw):
    for pattern in patterns(*args, **kw):
        # This is a property that should return a callable, even if a string view name is given.
        callback = pattern.callback

        # No property setter is provided, so this will have to do.
        pattern._callback = login_required(callback)

        yield pattern

এটি ব্যবহার করা এটির মতো কাজ করে (কারণটির জন্য কলটি listপ্রয়োজনীয় yield)।

urlpatterns = list(login_required_patterns('', url(r'^$', home_view)))

0

আপনি সত্যিই এটি জিততে পারবেন না। আপনাকে অবশ্যই অনুমোদনের প্রয়োজনীয়তার একটি ঘোষণা করতে হবে। ভিউ ফাংশনটি না করে আপনি এই ঘোষণাটি অন্য কোথায় রাখবেন?

কলযোগ্য বস্তুর সাথে আপনার দর্শন ফাংশনগুলি প্রতিস্থাপনের বিষয়টি বিবেচনা করুন।

class LoginViewFunction( object ):
    def __call__( self, request, *args, **kw ):
        p1 = self.login( request, *args, **kw )
        if p1 is not None:
            return p1
        return self.view( request, *args, **kw )
    def login( self, request )
        if not request.user.is_authenticated():
            return HttpResponseRedirect('/login/?next=%s' % request.path)
    def view( self, request, *args, **kw ):
        raise NotImplementedError

তারপরে আপনি আপনার ভিউ ফাংশনের সাবক্লাস তৈরি করে LoginViewFunction

class MyRealView( LoginViewFunction ):
    def view( self, request, *args, **kw ):
        .... the real work ...

my_real_view = MyRealView()  

এটি কোনও লাইন কোড সংরক্ষণ করে না। এবং এটি "আমরা ভুলে গেছি" সমস্যাটিকে সহায়তা করে না। আপনি যা করতে পারেন তা হ'ল ফাংশনগুলি অবজেক্ট কিনা তা নিশ্চিত হওয়ার জন্য কোডটি পরীক্ষা করা। সঠিক শ্রেণির।

তবে তারপরেও আপনি কখনই বুঝতে পারবেন না যে ইউনিট পরীক্ষা স্যুট ছাড়াই প্রতিটি দৃশ্যের ফাংশনটি সঠিক।


5
আমি জিততে পারি না? তবে আমার জিততে হবে! হারানো কোনও বিকল্প নয়! তবে গুরুত্বের সাথে, আমি আমার লেখকের প্রয়োজনীয়তাগুলি এড়িয়ে যাওয়ার চেষ্টা করছি না। আমি যা ঘোষণার দরকার তা কেবল বিপরীত করতে চাই। সমস্ত ব্যক্তিগত মতামত ঘোষণার পরিবর্তে এবং জনসাধারণের সম্পর্কে কিছু না বলার পরিবর্তে, আমি সমস্ত জনসাধারণের দৃষ্টিভঙ্গি ঘোষণা করতে এবং ডিফল্টটি ব্যক্তিগত রাখতে চাই।
সাম্তেগর

এছাড়াও, ক্লাসের মতামতগুলির জন্য ঝরঝরে ধারণা ... তবে আমি মনে করি এই মুহুর্তে আমার অ্যাপ্লিকেশনটিতে কয়েকশ ভিউ পুনর্লিখন সম্ভবত একটি অ-স্টার্টার।
সাম্তেগর

@ সামট্রেগার: আপনাকে জিততে হবে? আমার একটি নতুন বেন্টলি নিতে হবে। সিরিয়াসলি। আপনি গ্রেপ্তার করতে পারেন def। আপনি defসমস্ত ভিউ মডিউলগুলিতে সমস্ত স্ক্যান করতে তুচ্ছভাবে খুব ছোট একটি স্ক্রিপ্ট লিখতে পারেন এবং নির্ধারণ করতে পারেন যে কোনও @ লগিন_প্রযুক্তি ভুলে গিয়েছিল কিনা।
এস .লট

8
@ এস.লট এটি করার সবচেয়ে লম্বাতম উপায়, তবে হ্যাঁ, আমি অনুমান করি এটি কার্যকর হবে। আপনি কীভাবে জানেন যে কোন ডিফগুলি দর্শন রয়েছে? স্রেফ ভিউ.পি-তে ফাংশনগুলি দেখলে কাজ হবে না, হেল্পার ভাগ করে নেওয়া ফাংশনগুলিকে @ লগিন_প্রযুক্তি লাগবে না।
সমত্রেগর

হ্যাঁ, এটা খোঁড়া। প্রায় খোঁড়া আমি ভাবতে পারি। আপনি যা জানেন না সেগুলি পরীক্ষা করে বাদ দিয়ে কোন ডিফগুলি দেখায় urls.py
এস .লট

0

urlsএই ধরণের প্যাকেজগুলি https://github.com/vorujack/decorate_url ব্যবহার করে এটির সাজানোর জন্য এবং এর জন্য এটি সাজানোর জন্য সমস্ত ক্ষেত্রে একটি একক সূচনা পয়েন্ট পাওয়া সম্ভব ।


0

একটি অ্যাপ্লিকেশন রয়েছে যা এটিতে একটি প্লাগ-ও-প্লে সমাধান সরবরাহ করে:

https://github.com/mgrouchy/django-stronghold

pip install django-stronghold
# settings.py

INSTALLED_APPS = (
    #...
    'stronghold',
)

MIDDLEWARE_CLASSES = (
    #...
    'stronghold.middleware.LoginRequiredMiddleware',
)
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.