رفتن به مطلب
برای استفاده از انجمن و عضـویت کلیک کنید.

AnswerCenter

مرکز پاسخگویی به سوالات برنامه نویسی

درخواست سفارش پروژه

اطلاعیه

کاربر گرامی

به انجمن برنامه نویسی AnswerCenter.ir خوش آمدید

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


hossein_DW

ثبت نام ، ورود و ارسال درخواست امن با توکن رتروفیت

پست های پیشنهاد شده

hossein_DW    3

کاربر عادی

سلام 

مشکل در ثبت نام، ورود و ارسال درخواست های امن از مواردیه که زیاد در موردش پست میبینم و چون مبحث امنیت مبحث خیلی مهمیه که تا قبل از یادگیریش، خودمم برای گرفتن پروژه استرس های زیادی داشتم به این فکر افتادم که دانش و تجربه خودم در این زمینه رو با شما برنامه نویسان عزیز در میون بزارم.و برای ارسال درخواست هامون به سرور چه کتابخونه ای بهتر،منظم تر،زیبا تر، فوق العاده تر و غیره تر از retrofit2 نازنین :bigsmile: .

 

خب اول کد رو قرار میدم بعدش میرم سراغ توضیحات .

1. import android.content.Context;
2. import android.content.SharedPreferences;
3. import java.util.concurrent.TimeUnit;
4. import okhttp3.OkHttpClient;
5. import okhttp3.Request;
6. import project.main.G;
7. import project.utils.Config;
8. import project.utils.Constant;
9. import retrofit2.Retrofit;
10. import retrofit2.converter.gson.GsonConverterFactory;
11.
12.
13.
14. public class ApiClient {
15. private static Retrofit apiClient;
16. private ApiClient () {
17.  }
18. public static Retrofit getInstance() {
19.  if (apiClient == null ) {
20.  final SharedPreferences preferences = G.context.getSharedPreferences(Constant.LOCATION_PREF, Context.MODE_PRIVATE);
21.  OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
22.  .retryOnConnectionFailure(true)
23.  .readTimeout(20, TimeUnit.SECONDS)
24.  .connectTimeout(20, TimeUnit.SECONDS)
25.  .addInterceptor(chain -> {
26.  Request oldRequest = chain.request();
27.  Request.Builder newRequestBuilder = oldRequest.newBuilder();
28.   newRequestBuilder.addHeader("Accept","application/json");
29.   if (preferences.getString(Constant.PRE_USER_TOKEN,null) != null ) {
30.   newRequestBuilder.addHeader("token", preferences.getString(Constant.PRE_USER_TOKEN,null));
31.   }
32.   newRequestBuilder.method(oldRequest.method(),oldRequest.body());
33.   return chain.proceed(newRequestBuilder.build());
34.  })
35   .build();
36. apiClient = new Retrofit.Builder()
37.  .baseUrl(Config.BASE_URL)
38.  .addConverterFactory(GsonConverterFactory.create())
39.  .client(okHttpClient)
40.  .build();
41.  }
 42. return apiClient;
}

خط 19 با چک کردن نال بودن رتروفیت شروع به ساخت آن می کنیم

خط 20 با استفاده از کلاس Constantو متغیر استاتیک LOCATION_PREF و صد البته MODE_PRIVATE سراغ شیرد پرفرنس خود میرویم.

خط 21 با ایجاد یک نمونه از کلاس OkHttpClient متد های مورد نیاز را صدا میزنیم.

خط 25 با صدا زدن متد addInterceptor یک وقفه در ارسال درخواست ایجاد می کنیم(این وقفه به شکلی نیست که به نظر بیاید) تا بتوانیم به درخواست خود مقادیری اضافه کنیم.chain  موجود در این خط حاوی اطلاعاتی است که ما به سرور ارسال می کنیم.

خط 26 یک Request از کلاس OkHttpClient ایجاد کرده و با صدا زدن متد request از chain  به درخواست دسترسی پیدا می کنیم.

خط 27 با استفاده از دیزاین پترن Builder یک درخواست جدید ایجاد می کنیم. با این دیزاین پترن به Request دسترسی پیدا خواهیم کرد و میتوانیم آن را تغییر دهیم.

خط 28 با استفاده از متد addHeader میتوان هدر های متفاوتی ارسال کرد . در این خط ما نوع دریافت اطلاعات از سرور را تعیین می کنیم.

خط 29 الی 31 قسمت اصلی کار ما بحساب می آید. در این سه خط چک می کنیم که اگر کاربر توکن را در شیرد پرفرنسس موجود داشت، بعنوان هدر آن را ارسال کن.

سوال؟ چرا این کار را در interface انجام نمی دهیم. 1-وقتی کلاس قدرتمند OkHttpClient این امکان را در اختیار ما قرار داده چرا از آن استفاده نکنیم.2-فرض کنید در interface خود چندین درخواست به ادرس های مختلف سایت خود دارید که لازم است هدر را برای هر کدام ست کنید ،ترجیح میدهید کد های ارسال هدر را هر بار برای هر درخواست در interface قرار دهید و از خوانایی کد خود کم کنید یا آن را یک بار در کلاس اصلی خود بنویسید؟!

خط 32 از اونجایی که فقط نیاز به تغییر و افزودن هدر به درخواست خود داشتیم، با صدا زدن متد method دو پارامتر method و body را از oldRequest میگیریم و نه از newRequestBuilder.

خط 33 در این خط chain را با newRequestBuilder proceed  میکنیم و نتیجه را return 

کد هایی که تا به این جای کار زدیم بدین معنی است که ما کاری با درخواست و یا نوع درخواست POST یا GET نداریم فقط به اصطلاح توقفی ایجاد کرده و توکن خود را (برای امنیت بیشتر، رعایت نظم و خلاصه کردن کد نویسی) بعنوان هدر ارسال می کنیم.

خط 39 (هرگز نشه فراموش:) ) شرط انجام تمام مراحل بالا صدا زدن متد client و افزودن okHttpClient به آن است.

 

خط 30 بسیار مهم و اشکال زا است. توجه داشته باشید هر مدت addHeader دو پارامتر name و value دارد و ما در این خط توکن خود را با "token" نام گذاری کردیم. برای دریافت امن این توکن در سرور لازم است آن را به شکل زیر دریافت کنید.

$header = $_SERVER["HTTP_TOKEN"];

استفاده از عبارت HTTP_ و سپس نامی که در زمان ارسال توکن برایش انتخاب کردیم (البته با حروف بزرگ)  لازم الاجراست (اسم توکن رو بصورت دو تکه نه ارسال و نه دریافت کنید مثل"HTTP_TOKEN_USER" چون بازم خطا میده) در غیر اینصورت توکنی دریافت نخواهد شد(حداقل من نتونستم دریافت کنم، این PHP کلی مسخره بازی دراورد سرش و پوست از سرم کند).

نکته وقتی از اندروید Q  و به بعد استفاده می کنیم یا باید از پروتکل HTTPS اطلاعات رو دریافت کنید یا به فایل منیفست خود رفته و در تگ اپلیکیشن دو مورد زیر رو اضافه کنید.

android:usesCleartextTraffic="true"
tools:ignore="GoogleAppIndexingWarning,UnusedAttribute"

در آموزش های بعدی سراغ OAuth2 (ساخت توکن،رفرش توکن ، تاریخ انقضای توکن ارسال اطلاعات خصوصی در ازای توکن صحیح) ،پروگارد، استفاده از HashMap  برای سهولت در استفاده از درخواست های رتروفیت و ... میریم.

 

import android.content.Context;
import android.content.SharedPreferences;

import java.util.concurrent.TimeUnit;

import okhttp3.OkHttpClient;
import okhttp3.Request;
import project.main.G;
import project.utils.Config;
import project.utils.Constant;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;

/**
 * Created by Asus on 4/16/2019.
 */

public class ApiClient {

  private  static Retrofit apiClient;

  private ApiClient () {

  }


  public static  Retrofit getInstance() {


    if (apiClient == null ) {
      final SharedPreferences preferences = G.context.getSharedPreferences(Constant.LOCATION_PREF, Context.MODE_PRIVATE);
      OkHttpClient okHttpClient = new OkHttpClient().newBuilder()
        .retryOnConnectionFailure(true)
        .readTimeout(20, TimeUnit.SECONDS)
        .connectTimeout(20, TimeUnit.SECONDS)
        .addInterceptor(chain -> {
          Request oldRequest = chain.request();
          Request.Builder newRequestBuilder = oldRequest.newBuilder();
          
          newRequestBuilder.addHeader("Accept","application/json");
//            Toast.makeText(G.context, ""+TokenContainer.getToken(), Toast.LENGTH_SHORT).show();
          if (preferences.getString(Constant.PRE_USER_TOKEN,null) != null ) {
            newRequestBuilder.addHeader("token", preferences.getString(Constant.PRE_USER_TOKEN,null));
          }

          newRequestBuilder.method(oldRequest.method(),oldRequest.body());

          return chain.proceed(newRequestBuilder.build());
        })
        .build();



      apiClient = new Retrofit.Builder()
        .baseUrl(Config.BASE_URL)
        .addConverterFactory(GsonConverterFactory.create())
        .client(okHttpClient)
        .build();
    }
    return apiClient;
  }

 

 

  • پسندیدن 3

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
mohammad-alone    562

کاربر فعال

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

 

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر
hossein_DW    3

کاربر عادی

در 3 ساعت قبل، mohammad-alone گفته است :

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

 

ممنون.

خوب در هر صورت که ما باید توکن رو برای چک کردن کاربر ارسال کنیم و تا جایی که من متوجه شدم ارسال توکن با روشی که گفتم مشکلی نداره، فقط طبق نظر شما باید با HTTPS انجام بشه درسته؟! خوشحال میشم در مورد روشتون کمی بیشتر توضیح بدید.

به اشتراک گذاری این ارسال


لینک به ارسال
به اشتراک گذاری در سایت های دیگر

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

مهمان
ارسال پاسخ به این موضوع ...

×   شما در حال چسباندن محتوایی با قالب بندی هستید.   حذف قالب بندی

  تنها استفاده از 75 اموجی مجاز می باشد.

×   لینک شما به صورت اتوماتیک جای گذاری شد.   نمایش به عنوان یک لینک به جای

×   محتوای قبلی شما بازگردانی شد.   پاک کردن محتوای ویرایشگر

×   شما مستقیما نمی توانید تصویر خود را قرار دهید. یا آن را اینجا بارگذاری کنید یا از یک URL قرار دهید.


×
×
  • جدید...