چرا اوپن سورس رو دوست دارم؟ داستان ادیت سورس فلسک
یکی از مباحثی که در خصوص اوپن سورس و نرمافزارهای ازاد مطرح میشه، همین امکان دسترسی و ویرایش سورس نرمافزار هستش. با این حال، به عنوان کسی که ۵-۶ سالی میشه که دارم از نرمافزارهای اوپن سورس استفاده میکنم، هیچوقت تفاوتش با یه نرمافزار متن بسته غیر از رایگان بودن برای من محسوس نبود.
مدتی پیش، در محل کارم لازم شد که در برنامهنویسی ها، با استفاده از api به سیستم لاگین بشیم، ولی این قابلیت به صورت پیش فرض وجود نداشت که باعث شد من مامور به حل این مشکل بشم. بعد از شاید ساعتها گردش توی نت، تنها راهحلی که تونستم پیدا بکنم، ادیت کردن سورس اصلی سیستم و اضافه کردن این قابلیت به فریم ورک اصلی بود.
این کار، حسابی بهم حال داد. چونکه برای اولین بار داشتم سورس یه پکیجی که تا حالا ازش فقط استفاده میکردم رو ادیت کردم که اونجوری که میخوام کار کنه. به قولی فکر کنم به این قضیه هک کردن یه سیستم هم میگن!
خوب، با این مقدمه کلی، بریم سراغ اینکه جریان چیه و چطوری اینکار رو کردیم.
دوستان مخاطب این وبلاگ، میدونن که من کلی ویدیوهای اموزش #فلسک دارم و از این فریم ورک کوچیک و خوشکل به عنوان فریم ورک اصلیم استفاده میکنم. با این حال، این پروژه برای راحتی استفاده و مدیریت بهتر وضعیت کاربری، از یکی از پکیج های کوچیک اضافه بر فلسک به نام Flask-AppBuilder استفاده میکنه. این پکیج، به صورت خیلی خلاصه براتون بگم که برای ایجاد کردن سریع یه بخش کاربری کامل هستش. شامل پریمشنها و مدیریت حسابهای کاربری و مسائل از این دست. خیلی سریع و دقیق با استفاده از یه سری پکیج های دیگه کارتون رو راه میندازه.
تنها نقطه ضعف این سیستم، لااقل برای من این بودش که امکان لاگین به سیستم با استفاده از api ها و JSON بهش لاگین کنیم و از امکاناتش استفاده کنیم. توی تحقیقات زیادی که من کردم، به این نتیجه رسیدم که چنین چیزی رو امکان نداره و باید هر شخص خودش انجام بده و چند بار هم اعلام کردن دولوپرهاش که اقاجون این قضیه رو ما پشتیبانی نداریم و برید خودتون ایمپلمنت کنین.
چند نفر هم این کار رو انجام داده بودند ولی خوب روشهاشون برای سیستمهای دیگهای مثل oauth گوگل و دیگر سیستمهای بزرگ بود.
اولین مسئله این هستش که شما باید بدونید وقتی با پایتون و توی محیط ویرچوالتون میزنید مثلا pip install flask-appbuilder، این میره در کجا نصب میشه.
/env/local/lib/python2.7/site-packages/flask_appbuilder/security/view.py
همونجوری که میبینید، سورس اصلی پکیجهای نصب شده توسط pip اگر در محیط مجازی باشه داخل پوشهٔ مجازی و در غیر اینصورت، در usr و محل نصب پایتون ۲.۷ هستش.
سورس اصلی فایل view.py شامل فایلهایی هست که در اون، view های ورود و خروج به سیستم و ریجستر کاربر قرار دارن. کافیه که یک تابع کوچیک به این فایل اضافه کنم.
#to class AuthDBView(AuthView):
@expose('/loginapi/', methods=['POST'])
def loginapi(self):
username = request.json['username']
password = request.json['password']
user = self.appbuilder.sm.auth_user_db(username, password)
if not user:
return jsonify({"result": "wrong credintials"})
login_user(user, remember=False) return jsonify({"result": "You are logged in!"})
در این کدها، که همونطور که اشاره کردم باید به کلاس AuthDBView اضافه بشن. این کلاس برای کنترل لاگین با یوزرنیم و پسورد هست. و این تابع باید به کلاس مربوط به خودش اضافه بشه.
خیلی قضیه ساده هست. یه متد تعریف میکنیم، که ریکوستهای پست(POST) رو دریافت میکنه، از جیسان دریافتی username,password رو میخونه. باقی ساختار این تابع بر اساس تابع اصلی سیستم fab(flask app builder) هستش که من سعی کردم برای حفظ امنیت کار و کیفیتش، دستکاری نکردم.
یه تست ساده و کد سریع کار میکنه.
همچنین سیستم نیاز داره کاربر بتونه از طریق به ریکوست روی apiها، از سیستم لاگاوت هم بشه.
کد این بخش رو برای کلاس عمومی Authview تعریف میکنیم. این کلاس کنترل عمومی کلاسها رو به عهده میگیره.
#to class AuthView(BaseView):
@expose('/logoutapi/')
def logoutapi(self):
logout_user() return jsonify({"result": "logged of succesfully"})
به همین سادگی و خوشمزگی.
در ادامه، پروژهٔ ما یه مسئلهٔ جالب دیگه داره. قرار هست که به این اپلیکیشن فلسک، از طریق به اپلیکیشن فلسک دیگه لاگین بکنیم. بنابراین فلسک باید اینجا وقتی تابعش فراخوانی میشه، یک ریکوست POST به سرور فرستاده بشه.
این کار برای این نیاز هست که ما میخوایم سشن دریافت کنیم و دخیره کنیم تا یکبار با api لاگین کنیم و از اون به بعد بتونیم استفاده کنیم.
من به صورت کلی از این کد در کلاینت استفاده میکنم.
import requests import json
دو ایمپورت از پکیجهای عمومی پایتون. اولی ریکوستس هستش که برای اسکریپکردن سایت قبلا در موردش توضیح دادم و چند ویدیو ساختم. پکیج جیسان هم برای کار کردن با دیکشنری ها و جیسان استفاده میشه و میتونه اونها رو به هم تبدیل کنه یا از محتوای اونها استفاده کنه.
r = requests.session()
متغییر r از سشنهای ریکوست رو داخل خودش ذخیره میکنه. و میتونیم از این به بعد، به عنوان یک شی از نوع ریکوستس استفاده کنیم.
s = r.post('http://0.0.0.0:8080/loginapi/', json={"username": "senaps", "password": "12345"})
داستان بسیار ساده هست. من یک دیکشنری شامل username, password درست میکنم که قطعا با یه رمز درست حسابی و قابل اطمینان در کنار نامکاربریم به کار گرفته میشه. تمام این دیکشنری با استفاده از json تبدیل به محتوای جیسان میشه. من این مقادیر رو با استفاده از شی r که از نوع کلاس requests هست و متد post به تابعی که ساخته بودم و ادرس سرورام میفرستم و محتوای نتیجه برگشت خورده رو که یا لاگین موفق، یا لاگین شکستخورده هستش در متغییر s ذخیره میکنم.
توجه کنید که ادرسی که دارم بهش محتوای جیسان لاگین رو میفرستم(loginapi) دقیقا برابر هست با همون متدی که قبلا در کلاس اصلی fab ساخته بودم. یعنی دارم همون متد لاگین رو صدا میزنم.
در ادامه، میتونم به ادرسهایی که نیاز به لاگین دارند، از طریق شبیه به متد زیر دسترسی پیدا کنم:
s = r.get('http://0.0.0.0:8080/home/index') return s.text
در اینجا، متد index یک view هستش که برای دیدنش کاربر باید لاگین باشه.
من کد کامل این ویرایشها رو در یک جیست روی گیتهاب ذخیره کردم که از اینجا قابل دسترسی هستش. اگر راجعبه نحوه پیاده سازی یا مسائل دیگه سوالی داشتید میتونید بپرسید.
البته این تابع در شرکت ما و برای به کارگیری شدن تغییرات دیگهای هم به خودش دید، با این حال به نظرم برای کاربرد این پست که همون ویرایش کردن سورس یه پکیج برای گرفتن نتیجهٔ دلخواه هستش، همین مقدار کد هم کفایت میکنه.
مطالعه بیشتر:
- فلسک اپ بیلدر(سورس| داکیومنت| سایت)
- جمعه, ۲۲ ارديبهشت ۱۳۹۶، ۱۱:۵۱ ب.ظ