跳转至

使用客户端 SDK 调用后端授权 API

使用 Authany SDK 调用您的应用服务器

在本节中,我们将说明如何使用 Authany SDK 向后端 API 发起授权请求。Authany SDK 让您可以轻松地在需要时刷新访问令牌,并维护会话状态。

如果您的 Web 应用使用基于 Cookie 的身份验证,可以跳过本节,因为会话 Cookie 会由浏览器自动处理。

概述

  1. 为了确定是哪个用户在调用您的服务器,您需要在发送给应用服务器的每个请求中都包含 Authorization 请求头。
  2. 在您的后端/API 中,您需要完成后端集成。Authany 会帮助您处理 Authorization 请求头,判断传入的 HTTP 请求是否已通过身份验证。

下面的章节将说明如何配置 SDK,以便向后端发起授权 API 调用。

SDK 设置

使用 Authany 端点和 client id 配置 Authany SDK。使用前必须先调用 configure 对 SDK 进行正确配置。调用 configure 期间不会触发任何网络请求。

authgear
    .configure({
        clientID: "<YOUR_APPLICATION_CLIENT_ID>",
        endpoint: "<YOUR_AUTHGEAR_ENDPOINT>",
    })
    .then(() => {
        // configured successfully
    })
    .catch((e) => {
        // failed to configured
    });
let authgear = Authgear(clientId: clientId, endpoint: endpoint)
authgear.configure() { result in
    switch result {
    case .success():
        // configured successfully
    case let .failure(error):
        // failed to configured
    }
}
ConfigureOptions configureOptions = new ConfigureOptions();
Authgear authgear = new Authgear(getApplication(), clientID, endpoint);
authgear.configure(configureOptions, new OnConfigureListener() {
    @Override
    public void onConfigured() {
        // configured successfully
    }

    @Override
    public void onConfigurationFailed(@NonNull Throwable throwable) {
        // failed to configured
    }
});
var authgearOptions = new AuthgearOptions
{
    ClientId = "<YOUR_APPLICATION_CLIENT_ID>",
    AuthgearEndpoint: "<YOUR_AUTHGEAR_ENDPOINT>",
};
#if __ANDROID__
var authgear = new AuthgearSdk(GetActivity().ApplicationContext, authgearOptions);
#else
#if __IOS__
var authgear = new AuthgearSdk(UIKit.UIApplication.SharedApplication, authgearOptions);
#endif
#endif
await authgear.ConfigureAsync();

UserInfo 与会话状态

sessionState 反映用户的登录状态。不过会话状态是在本地缓存的,只有在每次服务器调用之后才会更新。

通常在通过 authorize 完成登录/注册后,一旦 authgear.sessionState 变为 AUTHENTICATED,您就应该尽快调用 fetchUserInfo。

// value can be NO_SESSION or AUTHENTICATED
// After authgear.configure, it only reflect SDK local state.
let sessionState = authgear.sessionState;

if (sessionState === "AUTHENTICATED") {
    authgear
        .fetchUserInfo()
        .then((userInfo) => {
            // sessionState is now up to date
            // read the userInfo if needed
        })
        .catch((e) => {
            // sessionState is now up to date
            // it will change to NO_SESSION if the session is invalid
        });
}
// value can be .noSession or .authenticated.
// After authgear.configure, it only reflect SDK local state.
let sessionState = authgear.sessionState

// call fetchUserInfo to see if the session is valid
if authgear.sessionState == .authenticated {
    authgear.fetchUserInfo { userInfoResult in
        // sessionState is now up to date
        // it will change to .noSession if the session is invalid
        let sessionState = authgear.sessionState

        switch userInfoResult {
        case let .success(userInfo):
            // read the userInfo if needed
        case let .failure(error):
            // failed to fetch user info
            // the refresh token maybe expired or revoked
    }
}
// value can be NO_SESSION or AUTHENTICATED
// After authgear.configure, it only reflect SDK local state.
SessionState sessionState = authgear.getSessionState();

if (sessionState == SessionState.AUTHENTICATED) {
    authgear.fetchUserInfo(new OnFetchUserInfoListener() {
        @Override
        public void onFetchedUserInfo(@NonNull UserInfo userInfo) {
            // sessionState is now up to date
            // read the userInfo if needed
        }

        @Override
        public void onFetchingUserInfoFailed(@NonNull Throwable throwable) {
            // sessionState is now up to date
            // it will change to NO_SESSION if the session is invalid
        }
    });
}
// value can be NoSession or Authenticated
// After Authgear.ConfigureAsync, it only reflects local state.
var sessionState = authgear.SessionState;

if (sessionState == SessionState.Authenticated)
{
    try
    {
        var userInfo = await authgear.FetchUserInfoAsync();
        // sessionState is now up to date
    }
    catch (Exception ex)
    {
        // sessionState is now up to date
        // it will change to NoSession if the session is invalid
    }
}

发起 API 调用

当您向后端 API 发起调用时,需要在 Authorization 请求头中包含访问令牌。出于安全考虑,访问令牌的有效期较短,需要定期使用刷新令牌进行轮换。Authany SDK 提供了以下函数来简化这两个步骤。

fetch 函数(仅限 JavaScript)

仅限 JavaScript。Authany SDK 提供了 fetch 函数,供您调用应用服务器。fetch 函数会自动在应用请求中包含 Authorization 请求头,并自动处理访问令牌的刷新。authgear.fetch 实现了 fetch 规范。

如果您使用的是其他网络请求库,则需要自行调用 refreshAccessTokenIfNeeded(). 并按下一段所述自行添加 Authorization 请求头。

authgear
    .fetch("YOUR_SERVER_URL")
    .then(response => response.json())
    .then(data => console.log(data));

refreshAccessTokenIfNeeded 函数

您需要在应用请求中包含 Authorization 请求头。每次使用访问令牌之前都调用 refreshAccessTokenIfNeeded,该函数只有在访问令牌已过期时才会检查并发起网络请求。然后将访问令牌加入应用请求的 Authorization 请求头中。

authgear
    .refreshAccessTokenIfNeeded()
    .then(() => {
        // access token is ready to use
        // accessToken can be string or undefined
        // it will be empty if user is not logged in or session is invalid
        const accessToken = authgear.accessToken;

        // include Authorization header in your application request
        const headers = {
            Authorization: `Bearer ${accessToken}`
        };
    });
authgear.refreshAccessTokenIfNeeded() { result in
    switch result {
    case .success():
        // access token is ready to use
        // accessToken can be empty
        // it will be empty if user is not logged in or session is invalid

        // include Authorization header in your application request
        if let accessToken = authgear.accessToken {
            // example only, you can use your own networking library
            var urlRequest = URLRequest(url: "YOUR_SERVER_URL")
            urlRequest.setValue(
                "Bearer \(accessToken)", forHTTPHeaderField: "authorization")
            // ... continue making your request
        }
    case let .failure(error):
        // failed to refresh access token
        // the refresh token maybe expired or revoked
    }
}
// Suppose we are preparing an http request in a background thread.

// Setting up the request, e.g. preparing a URLConnection

try {
    authgear.refreshAccessTokenIfNeededSync();
} catch (OauthException e) {
    // failed to refresh access token
    // the refresh token maybe expired or revoked
}
// access token is ready to use
// accessToken can be string or undefined
// it will be empty if user is not logged in or session is invalid
String accessToken = authgear.getAccessToken();
HashMap<String, String> headers = new HashMap<>();
headers.put("authorization", "Bearer " + accessToken);

// Submit the request with the headers...
try
{
    await authgear.RefreshAccessTokenIfNeededAsync();
}
catch (OauthException ex)
{
    // failed to refresh access token
    // the refresh token maybe expired or revoked
}
// access token is ready to use
// accessToken can be string or undefined
// it will be empty if user is not logged in or session is invalid
var accessToken = authgear.AccessToken;
var client = GetHttpClient();  // Get the re-used http client of your app, as per recommendation.
var httpRequestMessage = new HttpRequestMessage(myHttpMethod, myUrl);
httpRequestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
// Send the request with the headers...

处理已撤销的会话

如果会话在管理台中被撤销,客户端会带着无效的访问令牌调用您的后端 API。您的应用服务器可以通过查看解析器请求头来检测这种情况。

例如,您的应用可以对未授权的请求返回 HTTP 状态码 401。根据您应用的具体流程,您可能希望重新向用户展示登录页面,或者在本地将 SDK 的 sessionState 重置为 NO_SESSION。要清除 sessionState,可以使用 clearSessionState 函数。

// example only
// if your application server return HTTP status code 401 for unauthorized request
async function fetchAppServer() {
    var response = await authgear.fetch("YOUR_SERVER_URL");
    if (response.status === 401) {

        // if you want to clear the session state locally, call clearSessionState
        // `authgear.sessionState` will become `NO_SESSION` after calling
        await authgear.clearSessionState();
        throw new Error("user session invalid");
    }
    // ...
}
// example only
// if your application server return HTTP status code 401 for unauthorized request
if let response = response as? HTTPURLResponse {
    if response.statusCode == 401 {

        // if you want to clear the session state locally, call clearSessionState
        // `authgear.sessionState` will become `.noSession` after calling
        authgear.clearSessionState { result in
            switch result {
            case .success():
                // clear SDK session state locally
                // `authgear.sessionState` becomes `.noSession`
            case let .failure(error):
                // failed to clear session state
            }
        }
    }
}
// example only
// if your application server return HTTP status code 401 for unauthorized request
responseCode = httpConn.getResponseCode();
if (responseCode == HttpURLConnection.Unauthorized) {

    // if you want to clear the session state locally, call clearSessionState
    // `authgear.getSessionState()` will become `NO_SESSION` after calling
    authgear.clearSessionState();
}
// example only
// if your application server return HTTP status code 401 for unauthorized request
statusCode = httpResponseMessage.StatusCode;
if (statusCode == HttpStatusCode.Unauthorized)
{
    // if you want to clear the session state locally, call ClearSessionState
    // `authgear.SessionState` will become `NoSession` after calling
    authgear.ClearSessionState();
}