1. ホーム
  2. c#

[解決済み] 不正な webapi 呼び出しにより、401 ではなく、ログインページが返される

2022-04-15 04:03:15

質問

mvc/webapi プロジェクトを設定して、razor ビューから呼び出された webapi メソッドが、未承認時にログインページを返さないようにするにはどうすればよいですか?

MVC5アプリケーションで、javascript経由で呼び出すためのWebApiコントローラも持っています。

以下の2つのメソッド

[Route("api/home/LatestProblems")]      
[HttpGet()]
public List<vmLatestProblems> LatestProblems()
{
    // Something here
}

[Route("api/home/myLatestProblems")]
[HttpGet()]
[Authorize(Roles = "Member")]
public List<vmLatestProblems> mylatestproblems()
{
   // Something there
}

は以下のangularのコードで呼び出されます。

angular.module('appWorship').controller('latest', 
    ['$scope', '$http', function ($scope,$http) {         
        var urlBase = baseurl + '/api/home/LatestProblems';
        $http.get(urlBase).success(function (data) {
            $scope.data = data;
        }).error(function (data) {
            console.log(data);
        });
        $http.get(baseurl + '/api/home/mylatestproblems')
          .success(function (data) {
            $scope.data2 = data;
        }).error(function (data) {
            console.log(data);
        });  
    }]
);

つまり、ログインしていない状態で、[Authorize]のスタンプが押されたコントローラアクションをリクエストした場合に、mvcで得られるものです。

ログインしているかどうかに応じて、ユーザーに異なるデータを表示できるように、401の未承認を返したいのです。 理想的には、ユーザーがログインしている場合、ControllerのUserプロパティにアクセスして、そのメンバーに固有のデータを返すことができるようにしたいのです。

UPDATE: 以下の提案がどれもうまくいかないようなので(IdentityやWebAPIの変更)、生の例を以下のページに作成しました。 ギズブ この問題を説明する必要があります。

解決方法は?

AuthorizeAttributeには2つの実装があり、Web APIの場合は正しい方を参照する必要があります。 以下のものがあります。 System.Web.Http.AuthorizeAttribute という、Web API で使用されるもの、および System.Web.Mvc.AuthorizeAttribute(システムウェブエクスチェンジアトリビュート)。 で、これはビューを持つコントローラに使用されます。 Http.AuthorizeAttribute は、認証に失敗すると401エラーを返します。 Mvc.AuthorizeAttribute はログインページにリダイレクトされます。

2013年11月26日更新

ブロック・アレンが指摘したように、MVC 5では状況が大きく変わったようです。 彼の記事で . OWINパイプラインが引き継ぎ、いくつかの新しい動作を導入しているのでしょう。 現在では、ユーザーが認証されていない場合、HTTPヘッダーに以下の情報を含む200のステータスが返されています。

X-Responded-JSON: {"status":401,"headers":{"location":"http:\/\/localhost:59540\/Account\/Login?ReturnUrl=%2Fapi%2FTestBasic"}}

クライアント側のロジックを変更して、エラーブランチで401ステータスを探すのではなく、ヘッダーのこの情報をチェックして処理方法を決定するようにすることができます。

私はこの動作をカスタム AuthorizeAttribute でレスポンスにステータスを設定することで OnAuthorization HandleUnauthorizedRequest メソッドがあります。

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

しかし、これではうまくいきませんでした。新しいパイプラインはこのレスポンスを後で取得し、私が以前取得していたのと同じレスポンスに変更する必要があります。 HttpExceptionを投げても、500エラーステータスに変更されるだけなので、これもうまくいきませんでした。

Brock Allen氏の解決策をテストしたところ、jQueryのajax呼び出しを使用した場合はうまくいきました。もしうまくいかないのであれば、それはあなたがangularを使用しているからだと思います。 Fiddlerでテストを実行し、以下のものがヘッダにあるかどうかを確認してください。

X-Requested-With: XMLHttpRequest

もしそうでないなら、それが問題なのです。私はangularに詳しくないのですが、もし独自のヘッダー値を挿入できるのであれば、これをajaxリクエストに追加すれば、おそらく動作し始めるでしょう。