[VB.NET] REST API⑮ BASIC認証
ASP.NET MVC ビューに複数のパラメーターを渡すで作成したサンプルを改造して、Web APIにBASIC認証の機能を実装してみましょう。
※ VisualStudio2019
認証をするための属性クラスを追加
BASIC認証をするための属性クラスを追加していきます。
このサンプルでは独自のフォルダを作って、その中に属性クラスを作成しています。
「App_Code」フォルダを使うといろいろ面倒なので 独自のフォルダ にしています。
ソリューションエクスプローラでプロジェクトを右クリックして、「追加」>「新しいフォルダー」をクリックします。
追加したフォルダーに名前を付けます。
このサンプルでは「Authorize」にしました。
ソリューションエクスプローラで、 追加した「Authorize」フォルダを右クリックして、「追加」>「クラス」をクリックします。
クラス名を入力し、「追加」をクリックします。
このサンプルでは、「UserAuthorizeAttribute」という名前にしています。
「UserAuthorizeAttribute」クラスを実装します。
このクラスは「AuthorizationFilterAttribute」を継承し、「OnAuthorization」メソッドをオーバーライドします。
この中でカスタム認証をおこない、最後に継承元のOnAuthorizationを呼び出します。
このサンプルではユーザー/パスワードは固定で「user1」/「password1」としています。
認証が失敗した場合は、エラーメッセージを返すようにしています。
コード
Imports System.Net
Imports System.Net.Http
Public Class UserAuthorizeAttribute
Inherits System.Web.Http.Filters.AuthorizationFilterAttribute
Public Overrides Sub OnAuthorization(actionContext As System.Web.Http.Controllers.HttpActionContext)
'カスタム認証を行う
'リクエスト情報を取得
Dim req As HttpRequestMessage
req = actionContext.Request
'リクエストヘッダーから認証情報を取得する
Dim auth As Headers.AuthenticationHeaderValue
auth = req.Headers.Authorization
'認証情報がNothing、またはスキームがbasic認証以外、またはパラメータが無いならエラー応答
If (auth Is Nothing) OrElse (auth.Scheme.ToLower <> "basic") OrElse (String.IsNullOrEmpty(auth.Parameter)) Then
actionContext.Response = req.CreateErrorResponse(HttpStatusCode.Unauthorized, "The authentication information is invalid")
Else
'認証情報を取り出す
Dim auth_param As String
auth_param = System.Text.Encoding.UTF8.GetString(System.Convert.FromBase64String(auth.Parameter))
'ユーザー名「user1」、パスワードが「password1」の組み合わせ以外はエラー応答
If auth_param <> "user1:password1" Then
actionContext.Response = req.CreateErrorResponse(HttpStatusCode.Unauthorized, "The authentication information is invalid")
End If
End If
'継承元のメソッド呼び出し
MyBase.OnAuthorization(actionContext)
End Sub
End Class
APIのコントローラーに認証機能をつける
APIのコントローラー(ApiTestController)に、認証機能をつけます。
やり方は簡単で、
<UserAuthorizeAttribute>
Public Class ApiTestController
Inherits ApiController
・・・
のように、属性を指定するだけです。
ビューのコントローラからAPIを呼び出し
続いてビューのコントローラー(ViewTestController)から、BASIC認証付きでAPIを呼び出し部分を実装します。
実装しているデフォルトのアクションは「Index」だけです。
ユーザー/パスワードは固定で「user1」/「password1」 とし、Base64でエンコードした文字列をヘッダーの「Authorization」にセットしています。
APIのGETが成功した場合と失敗した場合でそれぞれメッセージを表示しています。
コード
Imports System.Web.Mvc
Namespace Controllers
Public Class ViewTestController
Inherits Controller
' GET: ViewTest
Function Index() As ActionResult
'一覧を取得するAPIのURL
Dim url As String
url = DirectCast(Request, System.Web.HttpRequestWrapper).Url.GetLeftPart(UriPartial.Authority) & "/api/ApiTest"
Dim clt As New Net.Http.HttpClient
Dim result As New System.Net.Http.HttpResponseMessage
Dim bytes As Byte()
Dim auth_param As String
'ユーザー名「user1」、パスワード「password1」の認証情報をバイト配列に変換
bytes = System.Text.Encoding.UTF8.GetBytes("user1:password1")
'base64に変換
auth_param = System.Convert.ToBase64String(bytes)
'ヘッダーに認証情報を入れる
clt.DefaultRequestHeaders.Authorization = New System.Net.Http.Headers.AuthenticationHeaderValue("basic", auth_param)
'GETを実行
result = clt.GetAsync(url).Result
Dim model As New ViewTestParam
If (result.StatusCode = Net.HttpStatusCode.OK) Then
'Jsonを取り出し
Dim json As String
json = result.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 = "データを取得しました!"
Else
'モデル作成
model.Item1 = New List(Of Record)
model.Item2 = "データの取得に失敗しました!" & result.Content.ReadAsStringAsync.Result
End If
Return View(model)
End Function
End Class
End Namespace
ビュー(index.vbhtml)は変更なしです。
@ModelType ViewTestParam
@Code
ViewData("Title") = "index"
End Code
<h2>index</h2>
@Html.Label("message_label", Model.Item2, New With {.style = "color:red;"})
<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>
実行して確認する
さっそく実行してみましょう。実行方法はこちらを参照してください。
まずはブラウザで直接APIのGETを呼び出してみます。
ユーザー/パスワードで認証をしていないので、エラーメッセージが表示されるようになりました。
次に、ビューから呼び出してみます。
アドレスバーに「/ViewTest/index」と入力してEnterキーを押してページを移動します。
正しいユーザー/パスワードが設定されているので、認証が成功してデータが取得できます。
続いて、パスワードを少し変えて、わざと間違ったパスワードを送ってみます。
このサンプルでは、「password1」→「NG_password1」にしています。
再度実行してみましょう。
認証エラーのメッセージが表示され、データの取得が失敗したので、認証が機能していることが確認できました。
WEB APIにBASIC認証機能を実装してみました。
イントラ内のシステムで、ちょっとした認証をつけたい場合なんかに利用できます。