ورود کاربر و دریافت توکن

برای فراخوانی متدهای محافظت شده که به داده‌های کاربر دسترسی می‌دهند یا آنها را ویرایش می‌کنند نیاز است توکن احراز هویت کاربر را در اختیار داشته باشید. این توکن با فراخوانی متد login در دسترس قرار می‌گیرد.

متد login

دو ورودی نام کاربر (ایمیل، username) و رمز یا کلمهٔ عبور او (password) را باید در رابط کاربری از خود او دریافت کنید. در ورودی clientAppName نام برنامهٔ خود را بگذارید. در ورودی language شاخص زبان را برابر با fa-IR قرار دهید (این ورودی مشخص می‌کند که پیغامهای خطا به چه زبانی برگردانده شود که غیر از فارسی به طور محدود از انگلیسی هم پشتیبانی می‌کند منتهی پشتیبانی آن به حدی نیست که بتوانید روی آن حساب کنید به همین دلیل حتماً از زبان فارسی استفاده کنید).

در صورتی که اطلاعات کاربر صحیح نباشد این متد BadRequest یا خطای 400 به همراه رشتهٔ حاوی پیغام خطا برمی‌گرداند.

نام کاربری و یا رمز نادرست است.

در صورت ورود موفقیت‌آمیز پاسخ وب‌سرویس ساختاری مطابق این کلاس #C است:

/// <summary>
/// Logged On User Model
/// </summary>
public class LoggedOnUserModel
{
    /// <summary>
    /// Session Id
    /// </summary>
    public Guid SessionId { get; set; }

    /// <summary>
    /// Security Token
    /// </summary>
    public string Token { get; set; }

    /// <summary>
    /// User Information
    /// </summary>
    public PublicRAppUser User { get; set; }

    /// <summary>
    /// Permissions
    /// </summary>
    public SecurableItem[] SecurableItem { get; set; }

}

مهمترین عضو ساختار فوق Token است که یک توکن از نوع JWT است و آن را برای تمام فراخوانی‌های محافظت‌شده نیاز دارید. این متغیر را ذخیره کنید.

عضو SessionId را هم برای گرفتن توکن جدید در صورت منقض شدن توکن موجود نیاز دارید.

از عضو User می‌توانید اطلاعات کاربر را دریافت کنید. از روی عضو SecurableItem می‌توانید فهرست دسترسی‌های کاربر را دریافت کنید. این دو عضو را برای فراخوانی متدهای وب‌سرویس نیاز ندارید. دسترسی‌ها به طور خودکار و در سمت وب‌سرویس کنترل می‌شود و در صورت عدم دسترسی، متدها وضعیت Forbidden با کد 403 را برمی‌گرداند.

نکته: در صورتی که از NET. استفاده می‌کنید با اضافه کردن نوگت RSecurityBackend به مدلهای از پیش تعریف شده برای زیرساخت تدبیر مؤدیان دسترسی خواهید داشت. در غیر این صورت مستندات خودکار api این ساختارها را جهت تبدیل به زبان برنامه‌نویسی مدنظرتان در اختیار می‌گذارد.

کد نمونه: برای مشاهدهٔ نمونهٔ نحوهٔ پیاده‌سازی ورود به تدبیر مؤدیان این فایل را ملاحظه بفرمایید.

نحوهٔ استفاده از توکن احراز هویت: توکن احراز هویت از نوع JWT است و آن را می‌بایست به همراه فراخوانی‌های محافظت شده ارسال کنید. نمونه کد زیر مربوط به پیاده‌سازی خروج از حساب کاربری در یک برنامهٔ ویندوزی است:

using (HttpClient httpClient = new HttpClient())
{

    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Properties.Settings.Default.Token);
    var response = await httpClient.DeleteAsync
        (
        $"https://api.moaddiyan.com/api/users/delsession?userId={loggedOnUser.User.Id}&sessionId={Properties.Settings.Default.SessionId}"
        );
    if (response.StatusCode != HttpStatusCode.OK)
    {
        Cursor = Cursors.Default;
        Enabled = true;
        MessageBox.Show(JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()));
        return;
    }
    response.EnsureSuccessStatusCode();
    

    Properties.Settings.Default.LoggenOnUserJson = "";
    Properties.Settings.Default.Token = "";
    Properties.Settings.Default.SessionId = Guid.Empty;
    Properties.Settings.Default.Save();

    Application.Restart();
}

تذکر مهم: توکن‌های احراز هویت تاریخ انقضا دارند و در صورت انقضا می‌توانند با فراخوانی متد relogin بدون نیاز به خارج و وارد شدن کاربر تمدید شوند. راهکار بهتر برای فراخوانی روالهای محافظت شدهٔ تدبیر مؤدیان آن است که این مسئله را هم لحاظ کنید. نمونه کد زیر راهکار همراه کردن توکن به HttpClient را در #C نشان می‌دهد:

/// <summary>
/// if user is logged in adds user token to <paramref name="secureClient"/> and then checks user session and if needs renewal, renews it
/// </summary>
/// <param name="secureClient"></param>
/// <param name="response"></param>
/// <returns></returns>
public static async Task<bool> PrepareClientAsync(HttpClient secureClient)
{
    if (string.IsNullOrEmpty(Properties.Settings.Default.Token) || Properties.Settings.Default.SessionId == Guid.Empty)
        return false;
    secureClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", Properties.Settings.Default.Token);
    var r = await secureClient.GetAsync($"https://api.moaddiyan.com/api/users/checkmysession/?sessionId={Properties.Settings.Default.SessionId}");
    if (r.StatusCode == HttpStatusCode.OK)
    {
        return true;
    }
    else
    if (r.StatusCode == HttpStatusCode.Unauthorized)
    {
        var reLoginUrl = $"https://api.moaddiyan.com/api/users/relogin/{Properties.Settings.Default.SessionId}";
        var reLoginResponse = await secureClient.PutAsync(reLoginUrl, null);
        if (reLoginResponse.StatusCode != HttpStatusCode.OK)
        {
            return false;
        }

        var json = await reLoginResponse.Content.ReadAsStringAsync();
        LoggedOnUserModel? loggedOnUser = JsonConvert.DeserializeObject<LoggedOnUserModel>(json);
        if (loggedOnUser != null)
        {
            secureClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", loggedOnUser.Token);
            
            Properties.Settings.Default.LoggenOnUserJson = json;
            Properties.Settings.Default.Token = loggedOnUser.Token;
            Properties.Settings.Default.SessionId = loggedOnUser.SessionId;
            Properties.Settings.Default.Save();
        }
        return true;

    }
    return false;
}

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

using (HttpClient httpClient = new HttpClient())
{
    await MoaddiyanSessionChecker.PrepareClientAsync(httpClient);
    var response = await httpClient.DeleteAsync
        (
        $"https://api.moaddiyan.com/api/users/delsession?userId={loggedOnUser.User.Id}&sessionId={Properties.Settings.Default.SessionId}"
        );
    if (response.StatusCode != HttpStatusCode.OK)
    {
        Cursor = Cursors.Default;
        Enabled = true;
        MessageBox.Show(JsonConvert.DeserializeObject<string>(await response.Content.ReadAsStringAsync()));
        return;
    }
    response.EnsureSuccessStatusCode();
    

    Properties.Settings.Default.LoggenOnUserJson = "";
    Properties.Settings.Default.Token = "";
    Properties.Settings.Default.SessionId = Guid.Empty;
    Properties.Settings.Default.Save();

    Application.Restart();
}