6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

アクセストークンが必要なWebAPIへのPowerShellでのアクセス方法

Posted at

#はじめに
 WebAPIの利用する際にWebAPIのアクセスに対するセキュリティを担保するために、アクセストークンを利用します。本ドキュメントでは、アクセストークンが必要なWebAPIにアクセスするために必要なアクセストークンをAADより入手する方法と、WebAPIにアクセストークンをセットして呼び出す方法に関して記述しています。

#アクセストークンの取得
アクセストークンをAAD(Azure Active Directory)より取得します。PowerShellで通常はバッチ処理などを作成すると思います。普通のアプリケーションの場合、ユーザーの認証をAADで行い、そのユーザーのアクセストークンを利用して各種リソースにアクセスしています。PowerShellのバッチの場合、このユーザーが存在しません。このため、PowerShellの場合、AADのアプリケーションを作成してもらい、そのアプリケーションのアプリケーションIDとシークレットキー(パスワードみたいなもの)をつかって、アクセストークンを利用して、リソースアプリケーション(WebAPIを提供するアプリケーション)にアクセスを行います。
 このため、PowerShellからアクセスを行う場合、あらかじめ下記の情報を管理者より入手しておきます。

表1-1 事前に入手する情報

項目 内容 備考
テナントID 認証を行うテナントIDです。今回は、シングルテナントを想定しています。
アプリケーションID PowerShellがアクセストークンを取得するために作成したアプリケーションのID
シークレットキー パスワードみたいなもの
スコープID 利用するリソースアプリケーションのスコープIDを取得します。※1

※1 アプリケーションを作成する際に、利用するリソースアプリケーションのスコープ、アプリケーションロールに作成したアプリケーション「API許可」を行っておく必要があります。APIの許可と必要な場合、管理者の承認を実施しておいてもらいます。

##アクセストークンの入手

#アクセストークンを取得するURLを入力します。
$path = "https://login.microsoftonline.com/{TenantId}/oauth2/token"
#ヘッタの情報(これは固定値)
$contentType = 'application/x-www-form-urlencoded'

#Bodyの情報を作ります。
$body = @{grant_type='client_credentials'
    scope='{スコープ名}/.default'
    client_id='クライアントID'
    client_secret='シークレットキー'
}

アクセストークンを取得するためにRestAPIを呼び出します。

#アクセストークンの取得(RestAPIを呼び出します。)
$Result = Invoke-WebRequest -Method POST -Uri $path -body $body -ContentType $contentType

アクセス結果よりトークンを取り出します。

#アクセストークンの取り出し
$Content = ConvertFrom-Json $Result.Content
$AccessToken = $Content.access_token

 アクセストークンは、Base64でコンバートされたJSONデーターです。このため、取得したクライアント側でも内容を見ることができます。(Ver2のトークン)

 取得したアクセストークンは、下記URLで見ることができます。
 https://jwt.ms/

キャプチャ.PNG

##WebAPIの呼び出し
取得したアクセストークンを利用して、WebAPIを呼び出します。 APIを呼び出すためには、APIのインタフェース仕様書が必要です。
 今回は、テスト用に動作させている、ローカルマシンにアクセスしています。

#アクセスするアプリケーションのURLを入力
$apiurl = "https://localhost:44363/api/Values"

#アクセストークンを設定します。
$header = @{
    "Authorization" = "Bearer $AccessToken"
    "Content-Type" = "application/json"
}

WebAPIを呼び出します。

#APIを呼び出します。
$Response = Invoke-WebRequest -Method Get -Uri $apiurl -Headers $header

今回は、Getアクセスなので、URIにパラメーター等が設定します。
もし、アクセストークンの有効期限などが切れている場合、Invoke-WebRequestコマンドは、エラーを出します。エラーが発生した場合、$Responseに値は、入りません。

#PowerShellのエラーメッセージ
PS C:\work> $Response = Invoke-WebRequest -Method Get -Uri $apiurl -Headers $header
Invoke-WebRequest : {"Message":"この要求に対して承認が拒否されました。"}
発生場所 :1 文字:13
+ $Response = Invoke-WebRequest -Method Get -Uri $apiurl -Headers $head ...
+             ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : InvalidOperation: (System.Net.HttpWebRequest:HttpWebRequest) [Invoke-WebRequest]WebException
    + FullyQualifiedErrorId : WebCmdletWebResponseException,Microsoft.PowerShell.Commands.InvokeWebRequestCommand

##実際の利用時の注意
通常のPowerShellの場合、1時間も2時間も処理をすることは少ないと思います。上記で取得したベアラートークンは、発行から1時間で有効期限が切れます。このため、長い処理を行う可能性がある場合、トークンの時間切れに対応する必要があります。
 しかしながら、WebAPIを呼び出すたびにアクセストークンを取得するコードは、お勧めしません。

だめな例

$oDataAllay  | % {
	#アクセストークンの取得

	#WebAPIの呼び出し
}

このように、呼び出すたびにアクセストークンを取得するコードは、自身のパフォーマンスとAADへの負荷を考えると適切ではありません。
少なくともこのような処理の場合、ループの外側で1回アクセストークンを取得するべきです。
そこで、以下に取得したアクセストークンから、アクセストークンの有効期限(切れる日付)を取得する方法を記載します。

$BreakToken = $AccessToken.Split(".")
$byte = [System.Convert]::FromBase64String($BreakToken[1])
$Tokenpayroad = ConvertFrom-Json([System.Text.Encoding]::Default.GetString($byte))

#expDay Get
$Secound =  $Tokenpayroad.exp
$ExpDate = ([datetime]"1970/1/1").AddSeconds($Secound)

上記コードで、$ExpDateにこのアクセストークンの有効期限を取得することができます。注意事項として、このアクセストークンの有効期限は、UTC時間なので、動作しているマシンのタイムゾーンを意識するか、「(Get-Date).ToUniversalTime()」を利用して現在時間を取得してアクセストークンの有効期限を比較してください。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?