نحوه کار کردن با Guardian در فونیکس و میکروسرویس


#1

با درود خدمت دوستان . برای امن سازی لاگین وم همینطور دریافت اطلاعات می خوام از Guardian استفاده کنم بر طبق یک آموزشی هم اون رو کانفیگ کردم که چندتا سوال برای پیش اومده .

من اومدم یک کنترلر ساختم به نام GuardianDemoWeb.UserController و کد زیر رو برای لاگین قرار دادم

def sign_in(conn, %{"password" => "password"}) do
    user = %{id: "1"}

# اینجا مکان دریافت یوزر و پسورد از دیتابیس هست 

    conn
    |> GuardianDemo.Guardian.Plug.sign_in(user)
    |> send_resp(204, "")
  end

چون می خوام تست کنم فعلنه یوزر و پسورد رو اومدم دستی زدم . یک کامنت هم بالا قرار دادم . پس اینطور که من متوجه شدم می یاییم . به این صورت اقدام می کنیم

def sign_in(conn, %{"password" => "password"}) do
    user = %{id: "1"}
# اگر در دیتابیس پسورد و یوزر درست بود حالا اجازه بده ادامه مسیر انجام بشه و به وسیله یوزر توکن درست بشه
    conn
    |> GuardianDemo.Guardian.Plug.sign_in(user)
    |> send_resp(204, "")
  end

حالا می یام درخواست با پست ارسال می کنم چون تو روتر هم پست اجرا کردم . بازخورد کد به شرح زیر هست :

HTTP/1.1 204 No Content

Set-Cookie: _guardian_demo_key=SFMyNTY.g3QAAAABbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAVpleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUpuZFdGeVpHbGhibDlrWlcxdklpd2laWGh3SWpveE5USXhPVGMwTnpFd0xDSnBZWFFpT2pFMU1UazFOVFUxTVRBc0ltbHpjeUk2SW1kMVlYSmthV0Z1WDJSbGJXOGlMQ0pxZEdraU9pSmtNbVJtTkdJeU1pMDBPVEl5TFRSaVl6a3RZalZpT1MweU1ETmtOVGN3TVdNeVlXVWlMQ0p1WW1ZaU9qRTFNVGsxTlRVMU1Ea3NJbk4xWWlJNklqRWlMQ0owZVhBaU9pSmhZMk5sYzNNaWZRLjJMN095WEJWTE5mUWhwbEVkWE9LVXJFQnhXZml3Y2QzQVFqcDZPcDlkSHpMVkppSEJxenk3TzlCU3NITnMyME50V0g2cDRxRnVVTTRtdk5JUmxlZnpB.5uceSC3Qmysp4gqCzJVoYIuyoY6VsM1dHzP6JLz5hX4; path=/; HttpOnly
Server: Cowboy
Date: Sun, 25 Feb 2018 10:45:10 GMT
Content-Length: 0
Cache-Control: max-age=0, private, must-revalidate
x-request-id: akbgpcj33673q48cuagokn2r953q1lh4

در کد بالا اومده _guardian_demo_key یک چنین چیزی داده فکر کنم توکن هست درسته ؟

تا اینجا اگر درست گفتم پس من مرحله ساخت توکن رو انجام دادم و اگر مشکلی هست بر اساس کامنت هایی که تو کد قرار دادم بفرمایید ویرایش کنم.

مرحله بعدی می ریم سمت اینکه ببنیم واقعا ما کی هستیم ؟

من بر اساس آموزش کدی رو زدم در کنترلرم به شرح زیر :

  def show(conn, params) do
    user = GuardianDemo.Guardian.Plug.current_resource(conn)

    send_resp(conn, 200, Poison.encode!(%{user: user}))
  end

متاسفانه در این بخش من مشکل دارم در آموزش توکنی که در بالا گرفته شد اصلا ارسال نشده در هر درخواست که بگه من کیم . و منم آدرس رو یک گت ارسال کردم دیدم بهم این ارور داده

HTTP/1.1 401 Unauthorized

Server: Cowboy
Date: Sun, 25 Feb 2018 10:50:23 GMT
Content-Length: 31
Cache-Control: max-age=0, private, must-revalidate
x-request-id: hohpa0sibj08g03j22dar6s9gjuse5pr

و بدنه ارور نیز به شرح زیر :

{"message":"no_resource_found"}

تا اینجا با یک مشکل پیش رفتیم و سر آخر می مونه دو رویداد یکی چک کردن دیتابیس که آیا این توکن با یوزری که کاربر می فرسته یکی هست که خوب از دیتابیس می گیره و می یاره یا می تونیم از ردیس استفاده کنیم که هی از دیتابیس نگیره چون باید هر چند ساعت یا دقیقه پاک بشه توکن می مونه خروج از سایت

برای خروج از سایت نیز اومده این آموزش

  def sign_out(conn, _params) do
    conn
    |> GuardianDemo.Guardian.Plug.sign_out()
    |> send_resp(204, "")
  end

رو زده ولی بازم متاسفانه در اینجا نیومده به این فانکشن بگه توکن من اینه ؟ که اون توکن رو بیاد و از بین ببره در کل من فکر می کنم این آموزش یا من اشتباه متوجه شدم یا ناقص کاملا

لینک آموزش :

هدف :

هدف من اینکه اول لاگین کنم یوزر و پسوردم در بانک اطلاعاتی چک بشه اگر اوکی بود به من یک توکن بده من روی موبایلم توکن رو جایی ذخیره کنم یا روی ری اکتم توی کدم ذخیره کنم یا کوکیش کنم این توکن رو و هر درخواستی که می خوام بفرستم مثل اینکه آخرین موزیک هارو بهم نشون بده این توکن بفرستم اگر برای گروه کاربری من بود و توکن درست بود برام اطلاعات رو چاپ کنه

سوال در مورد میکروسرویس :

آیا این مراحل ساخت توکن باید در دروازه api شکل بگیره و توکن درست بشه یا باید در میکروسرویس user مثلا شکل بگیره ؟ ای پی آی گیت وی فقط باید پروکسی باشه یا اینکارا رو باید خودش انجام بده ؟


آموزش استفاده از Guardian در الکسیر
#2

کار گاردین درسته که به روشی امنی انجام میشه اما ایمن سازی نیست، یک کتاب خونه JWT هست.
البته این روش auth کمک زیادی به امنیت میکنه.
نه پروکسی از توکن چیزی ندونه بهتره


#3

ممنون توماج جان .من الان دو مشکل ریز دارم که در بالا گفتم . یکی تابع من کی هستم و یکی دیگه تابع خروج هست .

و اینکه من هر اطلاعاتی که می خوام بفرستم برای سرور چطور بفرستم ؟ که اینور بگیره کد شده . این مشکل بالا هست خدمتتون گفتم

در مورد پروکسی ممنون اطلاعات دادی چشم روی خود میکروسرویس این مورد رو انجام می دم ممنون از راهنماییت


#4

در مورد اینکه توکن کجا درست بشه بستگی بازم به معماری داره، اگر از یک سرویس(البته من به اینها نمیگم میکرو سرویس) برای auth استفاده میکنی، اون سرویس میتونه منبع اصلی و تولید کننده توکن باشه و خود اون سرویس به روش امنی با بقیه یا از طریق پروکسی در زمینه auth کار exchange رو انجام بده (authorization service). بازم باید دوباره با دقت بخونم و پاسخ بدم، ممکنه درست متوجه نشده باشم. من در این زمینه تجربه خوبی دارم اما بازم همیشه یک روش بهتر وجود داره


#5

متن رو تغییر دادم :broken_heart:


#6

من فکر می کنم کلا این آموزشی که من باهاش جلو رفتم در زمینه کار کردن با گاردین ناقصه چون الان سمپل کد هایی که دیدم. خیلی کد بیشتر داشتن


#7

در زمینه auth سعی کن قبل از هر چیز به معماری فکر کنی تا کد، یک روش مناسب رو که انتخاب کردی و مدل پروتوتایپ که درست شد سعی کن کدنویسی کنی، این از اون مواردیه که میتونه آینده پروژه رو تحت الشعاع قراربده.

یه نگاهی به لینک زیر بنداز، چیزی که توضیح داده برای پروژه شما شروع خوبی بنظر میاد

و این یکی، البته ای کاش کمتر از kubernate میگفت و روی اصل موضوع تمرکز داشت


#8

ممنون توماج جان . من این طرح رو قبل از شروع کارم کشیده بودم

من اینجوری فکر می کردم درسته البته نمی دونم این کارم درست هست یا نه :

۱. کاربر از موبایل می یاد یوزر پسورد خودشو می فرسته به پروکسی
۲. پروکسی می یاد یوزر پسورد می ده به login&user&ACL
۳. بعد براش یک توکن ایجاد می شه
۴. حالا می یاد در redis ذخیره می شه این توکن
۵. تو موبایل هم این توکن ذخیره می شه
۶. حالا کاربر می خواد از میکروسرویس ۱ اطلاعات بگیره توکن و یوزر می فرسته
۷. توکن و یوزر می یاد تو اون redis چک می شه وجود داره یا نه و انقضاش مشخص می شه
۸. یک درخواست می ره به login&user&ACL که ببینه نوع کاربریش چی هست مدیریت هست یا …
۹. تایید حویت شد یک درخواست می ره به میکروسرویس ۱
۱۰. اطلاعات به پروکسی برگشت داده می شه و پروکسی هم می یاد اطلاعات رو به موبایل برگشت می ده

دو مشکل :

۱. مشکل اول اینکه من با کتابخونه گاردین در اول راه نتونستم کار کنم و توش دچار مشکل شدم که باید حل کنمش و به همین منظور پست زدم

۲. آیا معماری من درست هست یا خیر ؟ یا اصلا نیاز به توکن داریم یا نه ؟ چون من توکن رو فقط برای اینکه هر دفعه به جدول login&user&ACL نره دارم درست می کنم ولی بازم برای سطح دسترسی به این جدول می ره . فکر می کردم بعد از ذخیره شدن توکن توی ردیسی که به api وصله از درخواست های خود این سرویس و دیتابیسش کم می کنم

و موردی که من خلی دنبالش هم هستم اینکه علاوه بر دسترسی بتونم تمامی اطلاعات از طرف کاربر ارسال می شه رو رمز شده دریافت کنم و تو سرور ذخیره کنم حالا چه توی موبایل باشه چه بر روی یک سایت که با ری اکت نوشته شده. البته لازم به ذکر هست روی سایت https هم هست


#9

اصطلاحات فارسیشو بعضیارو‌متوجه نمیشم، اگر انگلیسیش هم بود بهتر میشد.
منظورم سایت‌ گرافیگ بود. با گوشی سخته ببخشید


#10

ممنون توماج عزیز مثل همیشه وقت می زارید کمک می کنی @toomaj یک وب سرویس هست که همه استفاده می کنند هم موبایل هم قسمت سایت گرافیکی .

حالا امید وارم اساتید عزیز دیگه هم مثل @samdvr عزیز و همینطور @lxsameer عزیز هم کمک می کنند . اصلی ترین بخش کل نرم افزارم فکر کنم این بخش هست. شدیدا دارم سرچ می زنم اشتباه نرم جلو این بخش رو


#11

خیلی خوبه اگه به macaroons یه تگاهی بندازی خیلی کارت رو ساده تر می کنه.


#12

سلام شهریار جان
کار شما غلط نیست از نظر معماری خوبه
دو نوع کلی auth وجود داره یکی serverside روش الان شما
یکی clientside که با استفاده از JWT یا macaroons
client از نظراتی ساده تره اما token برای دراز مدت موجوده

حالا هر روشی انجام میدی مهم اینکه از کتابخانه معتبر برای این کار استفاده کنی


#13

سمیر جان سرچ می زنم اسم یک شیرینی می یاد وسط :grin:


#14

درود خدمت اساتید محترم .

ممنون از سام عزیز توماج و همینطور سمیر محترم . یکمی دیگه فشار بیارم ببنیم می تونم این بخش گاردین رو اوکی بکنم

چون @samdvr عزیز من بر اساس همین آموزش و یک آموزش دیگه رفتم ولی یک جاهای مشکل خوردم حالا با این دوتا پست مخصوصا دومی می رم جلو ببنیم جواب می ده اگر نداد دوباره مزاحم می شم

این آموزش دیدم

متاسفانه قدیمی هست خیلی از موارد کلا تغییر کرده فکر می کنم


#15

https://evancordell.com/2015/09/27/macaroons-101-contextual-confinement.html
http://macaroons.io/


#16

درود سام عزیز من این دو آموزش رو باز کامل تر دیدم مثل اینکه نسخه جدید اومده سریالیزر و … حذف شده .

من منبع خودمو آپلود کردم در گیت هاب

در پست اول من اومدم دقیقا تمام موارد رو انجام دادم دوباره کمی تمیز کاری کردم .

الان یک درخواست POST دادم به آدرس زیر
http://localhost:4000/api/users/sign-in

وقتی می زنم به من

HTTP/1.1 204 No Content

Set-Cookie: _api_trangell_key=SFMyNTY.g3QAAAABbQAAABZndWFyZGlhbl9kZWZhdWx0X3Rva2VubQAAAVdleUpoYkdjaU9pSklVelV4TWlJc0luUjVjQ0k2SWtwWFZDSjkuZXlKaGRXUWlPaUpoY0dsZmRISmhibWRsYkd3aUxDSmxlSEFpT2pFMU1qRTVPVGt6TVRVc0ltbGhkQ0k2TVRVeE9UVTRNREV4TlN3aWFYTnpJam9pWVhCcFgzUnlZVzVuWld4c0lpd2lhblJwSWpvaU9EVTFaVFEwTURVdE5UTTFOQzAwWWpVd0xUZ3daREF0TTJZNU5qWTROekJsTlRnMUlpd2libUptSWpveE5URTVOVGd3TVRFMExDSnpkV0lpT2lJeElpd2lkSGx3SWpvaVlXTmpaWE56SW4wLlc1ZGFQY3lUUms4cEg0TlprWm8teFVXckpkWTAyN2Qta0ZsSGRCcVJaSGdEWFlDYzYwZVh2VzdQb3VXeHJUTVh4UUpqbGpoMkpjNzlSUkN5NzVJZzZn.I5_3Grwm_FdKyWx4dKbtvsksLD1qJ3kI1Qzgsk5e_gM; path=/; HttpOnly
Server: Cowboy
Date: Sun, 25 Feb 2018 17:35:15 GMT
Content-Length: 0
Cache-Control: max-age=0, private, must-revalidate
x-request-id: 4tn7qid961v0qebqssuqb8bg2pi9nud2

می فرسته سوال اینجا پیش می یاد

۱. آیا _api_trangell_key= همان توکن هست ؟ با هربار درخواستی که می کنم این رو تغییر می ده . اگر هست پس این api درست شده است درسته ؟
‍‍‍۲. همین توکن رو باید در دیتابیس ذخیره کنم درسته؟

قطعه کدش در اینجا

جالبه که تابعی استفاده می کنه که برای خود فونیکس هست send_resp هست که بعد از اون هرچیزی می زارم ارور می گیره مثل رندر می مونه.
نکته : یک موردی که هست تمام موارد برگشت داده شده بالا در Response Headers می یاد نه در Response Body

تا اینجا مشکلات بالا رو داشتم . و همینطور دریافت توکن

مشکل بعدیم فکر کنم بعد از حل همین مشکل بیام بگم بهتره کم کم بره جلو . این حل بشه حتما یک ویدیو کامل ازش می گیره

چون مثلا بعد از اینکه توکن ساخته شد اومدم به لینک http://localhost:4000/api/users/me یک درخواست زدم متاسفانه

HTTP/1.1 401 Unauthorized

Server: Cowboy
Date: Sun, 25 Feb 2018 19:26:07 GMT
Content-Length: 31
Cache-Control: max-age=0, private, must-revalidate
x-request-id: oova1bt80qf7rc8kkkl2afr1d0ovl0tt

و همینطور Response Body زیر رو برام آورد

{"message":"no_resource_found"}

چقدر آموزش از این کم هست و خیلی هم قدیمی هستند اکثرا


#17

من اصلا اون خط رو ندیدم . اون که ست کوکی هست برای مروگر . پس اصلا نیاز ندارمش برای موبایل :disappointed_relieved:

اومدم جایگزینش کردم با خط

    {:ok, token, claims} = ApiTrangell.Guardian.encode_and_sign(user)

الان خروجی توکن رو گرفتم . من کلا تابع هایی که استفاده کردم فکر کنم اشتباه هست چون من اصلا کوکی نمی خوام بگیرم همش می خوام با توکن اطلاعات بگیرم و تنها چیزی که کوکی کنم خود توکن باشه . اونم بعد از دریافتش در فونیکس دیگه کوکیش کنم

کدمو ویرایش کردم به

	def sign_in(conn, %{"password" => password,}) do
		user = %{id: "1"}

		case password do
			2 ->
				{:ok, token, _claims} = ApiTrangell.Guardian.encode_and_sign(user)
				json conn, %Person{token: token}
				_ -> IO.puts "nabashe"  

		end 
	end

نمی دونم اینجوری نوشتم آیا مشکلی پیش می یاره از نظر امنیتی یا خیر؟


#18

شهریار جان مشکل شما حال شد یا هنوز درست نشده


#19

اینجا قبل اینکه token درست کنی password چک میکنی درسته دیگه ؟ در این صورت درسته


#20

درود سام عزیز . در پست بالا تصحیح کردم متنمو

فکر کنم مشکل گرفتن توکن حل شد . منبعمو هم آبدیت کردم .

حالا برای دی کد کردن می خوام تلاش کنم یک قطه کد نوشته به شرح زیر ویرایشاتی انجام دادم .

	def show(conn, %{"token" => token}) do

		{:ok, claims} = ApiTrangell.Guardian.decode_and_verify(token)
		# IO.puts claims
		json conn, %Person{token: "token"}
	end

بهم ارور ‍HTTP/1.1 401 Unauthorized بر می گردونه فکر کنم بخاطر روتر باشه

چون با بالا در یک خط فرق می کنه

الان این مشکل حل کنم می خواستم بعدش برم سمت revoke توکن که خودش گفته این برای مواردی هست که از پروسه زیر استفاده می کنند

revoke a token (use GuardianDb or something similar if you need revoke to actually track a token)

یا باید اینو نصب کنم یا اینکه این مورد اصلا به کار من نمی یاد