使用客户端 SDK 调用后端授权 API¶
使用 Authany SDK 调用您的应用服务器¶
在本节中,我们将说明如何使用 Authany SDK 向后端 API 发起授权请求。Authany SDK 让您可以轻松地在需要时刷新访问令牌,并维护会话状态。
如果您的 Web 应用使用基于 Cookie 的身份验证,可以跳过本节,因为会话 Cookie 会由浏览器自动处理。
概述¶
- 为了确定是哪个用户在调用您的服务器,您需要在发送给应用服务器的每个请求中都包含 Authorization 请求头。
- 在您的后端/API 中,您需要完成后端集成。Authany 会帮助您处理 Authorization 请求头,判断传入的 HTTP 请求是否已通过身份验证。
下面的章节将说明如何配置 SDK,以便向后端发起授权 API 调用。
SDK 设置¶
使用 Authany 端点和 client id 配置 Authany SDK。使用前必须先调用 configure 对 SDK 进行正确配置。调用 configure 期间不会触发任何网络请求。
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 请求头。
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();
}