[VB.NET] REST API⑭ OAuth2.0 認証#2(ビューから Web API を呼び出し)
前回で認証機能を実装したWeb APIをビューから呼び出してみましょう。
※ VisualStudio2019
ビューのコントローラーを実装
まずはビューのコントローラー「ViewTestController」のAPI呼び出し部分を作成していきます。
実装しているデフォルトのアクションは「Index」だけです。
テスト用に「GetToken」と「GetList」という独自のアクションを追加しています。
「GetToken」でAPIからアクセストークンを取得し、「GetList」でアクセストークンを付けてAPIを呼び出して一覧を取得します。
また、APIから取得したアクセストークンを保存するために「ApiToken」という内部クラスを定義しています。
「Models」フォルダ下にクラスを用意すればよかったのですが・・・まあいいか、とそのままにしています。
取得した「ApiToken」は一旦セッション変数に入れておき、一覧取得時にヘッダーのAuthorizationにセットしています。
コード
Imports System.Web.Mvc
Namespace Controllers
Public Class ViewTestController
Inherits Controller
''' <summary>
''' 認証トークン情報
''' </summary>
Friend Class ApiToken
''' <summary>アクセストークン</summary>
Property access_token As String
''' <summary>トークンタイプ</summary>
Property token_type As String
''' <summary>有効期限(TimeSpan)</summary>
Property expires_in As Long
''' <summary>取得した有効期限をDateTime型にしたもの</summary>
Property expires As DateTime
End Class
' GET: ViewTest
Function Index() As ActionResult
Session("token") = Nothing
'モデル作成
Dim model As New ViewTestParam With {.Item1 = New List(Of Record), .Item2 = ""}
Return View(model)
End Function
' POST: ViewTest/GetToken
<HttpPost()>
Function GetToken() As ActionResult
Try
'トークンを取得するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/Token"
'テスト用なのでユーザー/パスワードは固定
Dim user As String = "user1"
Dim pass As String = "password1"
'認証コード
Dim grant_type As String
grant_type = String.Format("grant_type=password&username={0}&password={1}", user, pass)
'コンテンツ作成
Dim content As System.Net.Http.StringContent
content = New System.Net.Http.StringContent(grant_type, New UTF8Encoding, "application/x-www-form-urlencoded")
'リクエストメッセージ
Dim req1 As System.Net.Http.HttpRequestMessage
req1 = New System.Net.Http.HttpRequestMessage(Net.Http.HttpMethod.Post, Url)
req1.Content = content
Dim clt As New Net.Http.HttpClient
Dim result As New System.Net.Http.HttpResponseMessage
'認証コードを要求
result = clt.SendAsync(req1).Result
Dim model As New ViewTestParam
If (result.StatusCode <> Net.HttpStatusCode.OK) Then
model.Item1 = New List(Of Record)
model.Item2 = "データの取得に失敗しました!" & result.Content.ReadAsStringAsync.Result
Return View("index", model)
End If
'Jsonを取り出し
Dim json As String
json = result.Content.ReadAsStringAsync.Result
'トークン取得
Dim _token As ApiToken
_token = Newtonsoft.Json.JsonConvert.DeserializeObject(Of ApiToken)(json)
'確認用にトークンの有効期限をDateTimeにしてみる
_token.expires = Now.AddSeconds(_token.expires_in)
'Session変数に保管
Session("token") = _token
'モデル作成
model.Item1 = New List(Of Record)
model.Item2 = String.Format("アクセストークンを取得しました! (有効期限:{0}秒)", _token.expires_in)
Return View("index", model)
Catch
Return View()
End Try
End Function
' POST: ViewTest/GetList
Function GetList() As ActionResult
Try
Dim model As New ViewTestParam
If IsNothing(Session("token")) Then
'モデル作成
model.Item1 = New List(Of Record)
model.Item2 = "アクセストークンを取得してください。"
Return View("index", model)
End If
'トークン
Dim _token As ApiToken
_token = CType(Session("token"), ApiToken)
'一覧を取得するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest"
Dim clt2 As New Net.Http.HttpClient
Dim result2 As New System.Net.Http.HttpResponseMessage
'認証ヘッダーにアクセストークンを設定
clt2.DefaultRequestHeaders.Authorization = New Net.Http.Headers.AuthenticationHeaderValue("Bearer", _token.access_token)
'GETを実行
result2 = clt2.GetAsync(Url).Result
If (result2.StatusCode = Net.HttpStatusCode.OK) Then
'Jsonを取り出し
Dim json As String
json = result2.Content.ReadAsStringAsync.Result
'デシリアライズ
Dim rec_list As List(Of Record)
rec_list = Newtonsoft.Json.JsonConvert.DeserializeObject(Of List(Of Record))(Json)
'モデル作成
model.Item1 = rec_list
model.Item2 = "データを取得しました!"
ElseIf (result2.StatusCode = Net.HttpStatusCode.Unauthorized) Then
'認証トークン有効期限切れ
'モデル作成
model.Item1 = New List(Of Record)
model.Item2 = "アクセストークンを取得してください!" & result2.Content.ReadAsStringAsync.Result
Else
'モデル作成
model.Item1 = New List(Of Record)
model.Item2 = "データの取得に失敗しました!" & result2.Content.ReadAsStringAsync.Result
End If
Return View("index", model)
Catch
Return View()
End Try
End Function
End Class
End Namespace
ビューを実装
ビューを実装していきます。
といっても、「GetToken」アクションを呼び出すボタンと、「GetList」アクションを呼び出すボタンを追加するだけです。
コード
@ModelType ViewTestParam
@Code
ViewData("Title") = "index"
End Code
<h2>index</h2>
@Html.Label("message_label", Model.Item2, New With {.style = "color:red;"})
<hr />
@Using (Html.BeginForm("GetToken", "ViewTest", FormMethod.Post))
@<div class="form-horizontal">
<h4>Token</h4>
<div class="form-group">
<input type="submit" value="GetToken" class="btn btn-default" />
</div>
</div>
End Using
@Using (Html.BeginForm("GetList", "ViewTest", FormMethod.Get))
@<div class="form-horizontal">
<h4>GetList</h4>
<hr />
<div class="form-group">
<input type="submit" value="GetList" class="btn btn-default" />
</div>
</div>
End Using
<hr />
<table class="table">
<tr>
<th>
@*最初の要素が無くてもエラーにならないので心配しなくてOK*@
@Html.DisplayNameFor(Function(model) model.Item1.First().col1)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.Item1.First().col2)
</th>
<th>
@Html.DisplayNameFor(Function(model) model.Item1.First().col3)
</th>
<th></th>
</tr>
@For Each item In Model.Item1
@<tr>
<td>
@Html.DisplayFor(Function(modelItem) item.col1)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.col2)
</td>
<td>
@Html.DisplayFor(Function(modelItem) item.col3)
</td>
<td>
@*@Html.ActionLink("Edit", "Edit", New With {.id = item.PrimaryKey}) |
@Html.ActionLink("Details", "Details", New With {.id = item.PrimaryKey}) |
@Html.ActionLink("Delete", "Delete", New With {.id = item.PrimaryKey})*@
</td>
</tr>
Next
</table>
実行して確認する
さっそく実行してみましょう。実行方法はこちらを参照してください。
アドレスバーに「/ViewTest/index」と入力してEnterキーを押してページを移動してから、「GetToken」をクリックしてアクセストークンを取得します。
アクセストークンの取得に成功すると、メッセージとトークンの有効期限が表示されます。
トークンの有効期限が切れる前に「GetList」をクリックして一覧を取得してみましょう。
一覧の取得に成功すると、メッセージと取得した一覧が表示されます。
1分後(有効期限が切れた後)、もう一度「GetList」をクリックしてみましょう。
要求が拒否されたメッセージが表示され、トークンの有効期限がちゃんと機能していることが確認できます。
再度「GetToken」をクリックしてアクセストークンを取得しなおせば、一覧の取得ができるはずです。
OAuth認証(Bearer Token)を実装したWeb APIをビューから呼び出してみました。
いずれリフレッシュトークンの実装についてもやってみようと思います。