ویژگی‌های ابزار Microsoft Graph

ایجاد پروژه در مرکز مدیریت Azure Active Directory

یک پروژه باید در مرکز مدیریت Azure Active Directory برای کاربری با حساب MS Office ایجاد شود.

مراحل ایجاد یک پروژه در مرکز مدیریت Azure Active Directory

در ادامه یک آموزش گام به گام برای ایجاد یک پروژه در مرکز مدیریت Azure Active Directory آمده است.

۱. به Azure Active Directory بروید و با استفاده از اعتبارهای MS Office خود وارد شوید.

Azure Active Directory لینک - https://aad.portal.azure.com/

۲. ایجاد برنامه Azure AD در مستاجر شما.

در پنل سمت چپ، برچسب Azure Active Directory را کلیک کنید. این کار صفحه Azure Active Directory را باز می‌کند. در آن صفحه باید برچسب App registrations را ببینید. این نقطه شروع ثبت یک برنامه Azure AD است. این صفحه به شما امکان ایجاد برنامه جدید برای Azure AD را می‌دهد.

روی دکمه New registration کلیک کنید تا برنامه جدیدی ایجاد کنید.

todo:image_alt_text

۳. اکنون صفحه ثبت برنامه جدید را مشاهده خواهید کرد.

  • Name این نام برنامه شما خواهد بود.
  • Supported account types این بخش دسترسی را محدود خواهد کرد.

دکمه Register را کلیک کنید.

todo:image_alt_text

۴. باید صفحه برنامه‌های تازه ثبت‌شده را ببینید.

  • Application (client) ID شناسه برنامه شما.
  • Directory (tenant) ID شناسه مستاجر Azure AD.

todo:image_alt_text

۵. اجازه دادن به مجوزها برای Microsoft Graph API.

روی برچسب API permissions کلیک کنید.

Azure قبلاً به برنامه شما مجوزهای تفویض‌شده User.Read را اعطا کرده است. این مجوز به ما اجازه می‌دهد اطلاعات کاربر وارد شده را بخوانیم. این‌ها مجوزهای Microsoft Graph API هستند، که می‌توان آن‌ها را Scopes نامید.

فهرست کامل اسکوپ‌های Microsoft Graph API - https://docs.microsoft.com/en-us/graph/permissions-reference.

روی دکمه + Add a permission کلیک کنید و Microsoft Graph را انتخاب کنید.

روی Delegated permissions کلیک کنید. اکنون فهرستی از مجوزهای موجود برای Microsoft Graph API را می‌بینید.

مجوزهای مورد نیاز را انتخاب کنید، روی دکمه Add permissions کلیک کنید.

روی دکمه Grant admin consent کلیک کنید.

todo:image_alt_text

۶. اجازه دادن به جریان‌های کلاینت عمومی.

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

todo:image_alt_text

۷. ایجاد یک کلید برای برنامه

todo:image_alt_text

کلاس‌های کمکی

کلاس‌های کمکی زیر برای اجرای کدها در این بخش ضروری هستند. این کلاس‌ها صرفاً برای ساده‌سازی نمایش استفاده می‌شوند.

کلاس AzureROPCTokenProvider

یک نمونه از IGraphClient کلاس ساختن درخواست‌ها، ارسال آن‌ها به API Microsoft Graph و پردازش پاسخ‌ها را مدیریت می‌کند. برای ایجاد یک نمونه جدید از این کلاس، باید یک نمونه از ITokenProvider، که می‌تواند درخواست‌ها را به Microsoft Graph احراز کند.

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 * Azure resource owner password credential (ROPC) token provider
 * https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth-ropc
 * https://docs.microsoft.com/en-us/exchange/client-developer/exchange-web-services/how-to-authenticate-an-ews-application-by-using-oauth
 * https://portal.azure.com
 * https://developer.microsoft.com/en-us/graph/graph-explorer/#
 * token parser https://jwt.io
 * </p>
 */
class AzureROPCTokenProvider implements ITokenProvider {

    private static final String GRANT_TYPE = "password";

    private final String clientId;
    private final String clientSecret;
    private final String userName;
    private final String password;
    private final String tenant;
    private final String scope;

    private OAuthToken token;

    public AzureROPCTokenProvider(String tenant, String clientId, String clientSecret,
                                  String userName, String password, String[] scopeAr) {
        this.tenant = tenant;
        this.clientId = clientId;
        this.clientSecret = clientSecret;
        this.userName = userName;
        this.password = password;
        this.scope = joinToStr(scopeAr, " ");
    }

    public synchronized OAuthToken getAccessToken(boolean ignoreExistingToken) {
        if (this.token != null && !this.token.getExpired() && !ignoreExistingToken)
            return this.token;
        token = null;

        Map<String, String> tokenArgs = geToken();

        java.util.Calendar c = java.util.Calendar.getInstance();
        c.add(java.util.Calendar.SECOND, Integer.parseInt(tokenArgs.get("expires_in")));
        token = new OAuthToken(tokenArgs.get("access_token"), TokenType.AccessToken, c.getTime());
        return token;
    }

    public final OAuthToken getAccessToken() {
        return getAccessToken(false);
    }

    public void dispose() {
    }

    private String getEncodedParameters() {
        return "client_id=" + urlEncode(clientId) + "&scope=" + urlEncode(scope) + "&username=" + urlEncode(userName)
                + "&password=" + urlEncode(password) + "&grant_type="
                + urlEncode(GRANT_TYPE);
    }

    private String getUri() {
        if (tenant == null || tenant.trim().isEmpty())
            return "https://login.microsoftonline.com/common/oauth2/v2.0/token";
        else
            return "https://login.microsoftonline.com/" + tenant + "/oauth2/v2.0/token";
    }

    private Map<String, String> geToken() {
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(getUri()).openConnection();
            connection.setRequestMethod("POST");

            byte[] requestData = getEncodedParameters().getBytes(StandardCharsets.UTF_8);

            connection.setUseCaches(false);
            connection.setDoInput(true);
            connection.setDoOutput(true);
            connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
            connection.setRequestProperty("Content-Length", "" + requestData.length);

            final OutputStream st = connection.getOutputStream();
            try {
                st.write(requestData, 0, requestData.length);
            } finally {
                st.flush();
                st.close();
            }

            connection.connect();

            if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) {
                throw new IllegalAccessError("Operation failed: " + connection.getResponseCode() + "/" +
                        connection.getResponseMessage() + "\r\nDetails:\r\n{2}"
                        + readInputStream(connection.getErrorStream()));
            }

            String responseText = readInputStream(connection.getInputStream());

            Map<String, String> result = new HashMap<>();
            String[] fromJsonToKeyValue = responseText.replace("{", "").replace("}", "")
                    .replace("\"", "").replace("\r", "")
                    .replace("\n", "").split(",");
            for (String keyValue : fromJsonToKeyValue) {
                String[] pair = keyValue.split(":");
                String name = pair[0].trim().toLowerCase();
                String value = urlDecode(pair[1].trim());
                result.put(name, value);
            }

            return result;
        } catch (IOException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String urlEncode(String value) {
        try {
            return URLEncoder.encode(value, StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String urlDecode(String value) {
        try {
            return URLDecoder.decode(value, StandardCharsets.UTF_8.toString());
        } catch (UnsupportedEncodingException e) {
            throw new IllegalAccessError(e.getMessage());
        }
    }

    static String readInputStream(InputStream is) {
        if (is == null)
            return "";

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        StringBuilder result = new StringBuilder();
        String line;
        try {
            while ((line = reader.readLine()) != null) {
                result.append(line);
            }
        } catch (IOException e) {
            // ignore
        }
        return result.toString();
    }

    static String joinToStr(String[] arr, String sep) {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            if (i > 0)
                sb.append(sep);
            sb.append(arr[i]);
        }
        return sb.toString();
    }
}