質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

87.37%

C#のHttpClientでのCookieを使ったログインの維持

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 4,616

前提・実現したいこと

C#のHttpClientでURIにjsonデータを送り、ログインするというプログラムを作っています。
ログインすることはできたのですが、Cookieの保持がおそらくできておらず、ログイン後のユーザーの情報が得られません。勉強中で初歩的なものかもしれませんが教えていただきたいです。

発生している問題・エラーメッセージ

ログイン(http://developers.u-aizu.ac.jp/api?key=judgeapi/session_POST後に、ユーザーの"self"情報が得られない(ログインのみできる)

下のメッセージはselfのGET(http://developers.u-aizu.ac.jp/api?key=judgeapi%2Fself_GET)を送った時のメッセージです。

[{"id":1102,"code":"INVALID_REFRESH_TOKEN_ERROR","message":"This user is expired."}]```  

C#  ソースコード

class API  
{  
//Login  
private void Login()  
{  
string user, password;  
Console.WriteLine("username >>>");  
user = Console.ReadLine();  
Console.WriteLine("password >>>");  
password = Console.ReadLine();  
var task = Task.Run(() => {  
return Post_Login(user, password);  
});  
var result = task.Result;  
Console.WriteLine(task.Result); //ログイン情報の表示がされる  
}  

async public Task<string> Post_Login(string id, string pass)  
{  
var parameters = new Dictionary<string, string>()  
{  
};  
var json = "{\"id\":\"" + id + "\",\"password\":\"" + pass + "\"}";  
Console.WriteLine(json); //json確認用の表示  
var content = new StringContent(json, Encoding.UTF8, "application/json");  

// クッキー準備  
CookieContainer cc = new CookieContainer();  
cc.Add(new Uri("https://judgeapi.u-aizu.ac.jp"), new Cookie("test", "value"));  

using (var handler = new HttpClientHandler())  

using (var client = new HttpClient())  
{  
var response = await client.PostAsync($"https://judgeapi.u-aizu.ac.jp/session", content);  
var cookie = response.Headers.GetValues("Set-Cookie").First();  
Console.WriteLine("content ->> " + content);  
Console.WriteLine("cookie --> " + cookie + "\n");  
content.Headers.Add("Cookie", cookie);  

// クッキー設定  
handler.CookieContainer = cc;  
//クッキー保存  
cc = handler.CookieContainer;  
Console.WriteLine("cc --> " + cc.ToString());  

return await response.Content.ReadAsStringAsync();  
}  
}  

//GET関数 Get(URI)で実行  
private void Get(string URI)  
{  
var task = Task.Run(() => {  
return GET(URI);  
});  

string[] numbers = new string[100];  
String str = task.Result;  
System.Console.WriteLine(str); //selfデータの表示(ここでエラーが起きる)  
}  
async public Task<string> GET(string URI)  
{  
using (var client = new HttpClient())  
{  
var uri = $"" + URI + "";  

var response = await client.GetAsync(uri);  

//UTF-8として変換  

return await response.Content.ReadAsStringAsync();  
}  
}  
public static void Main(string[] args)  
{  
API obj = new API();  
obj.Login(); //ログインの関数を呼び出す  
obj.Get("https://judgeapi.u-aizu.ac.jp/self"); //selfデータを得る(この関数内でエラーが起きる)  

試したこと

selfのGETを送った際に、ユーザー認証がうまくいっていないので、おそらくCookieの保存がうまくいっていないのではと思いました。
https://teratail.com/questions/14551 色々調べてみたのですが解決できなかったです。

補足情報

visual studio for mac,.Net Framework4.7.2,

http://developers.u-aizu.ac.jp/index
のapiを使っています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2020/04/06 06:57

    クッキーではなくてトークンと言うことはないですか? Web API はベアラトークンを使うケースが多いように思います。

    キャンセル

回答 2

checkベストアンサー

+1

GETHttpClientを作り直してるからじゃないですか?
あとクッキーを使いたいだけなら、UseCookies = trueでいいんじゃないですかね。

using System;
using System.Diagnostics;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

namespace Questions251616
{
    static class Program
    {
        static async Task Main()
        {
            Console.Write("username >>>");
            var user = Console.ReadLine();

            Console.Write("password >>>");
            var password = Console.ReadLine();

            var obj = new API();
            var result = await obj.LoginAsync(user, password);
            Console.WriteLine(result);
            Console.WriteLine();

            var self = await obj.SelfAsync();
            Console.WriteLine(self);

            Console.ReadKey();
        }
    }

    public class API
    {
        // 長いw
        private static readonly HttpClient client = new HttpClient(new HttpClientHandler() { UseCookies = true, })
        {
            BaseAddress = new Uri("https://judgeapi.u-aizu.ac.jp/"),
        };

        public async Task<string> LoginAsync(string id, string pass)
        {
            var json = $@"{{""id"":""{id}"",""password"":""{pass}""}}";
            Debug.WriteLine(json);

            var content = new StringContent(json, Encoding.UTF8, "application/json");
            var response = await client.PostAsync("session", content);
            Debug.WriteLine($"content ->> {content}");

            if(response.Headers.Contains("Set-Cookie"))
            {
                var cookie = response.Headers.GetValues("Set-Cookie").First();
                Debug.WriteLine($"cookie --> {cookie}\n");
            }

            return await response.Content.ReadAsStringAsync();
        }

        public Task<string> SelfAsync() => GetAsync("self");

        public async Task<string> GetAsync(string uri)
        {
            var response = await client.GetAsync(uri);
            return await response.Content.ReadAsStringAsync();
        }
    }
}

.NET(Framework)のHttpClientの取り扱いには要注意という話 - Qiita
を見るとStaticUseCookies = trueも要注意なのですが^^;

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/04/07 00:27

    HttpClientを作り直していたので、GET関数内で全てリセットされていた(違う通信をはじめていたという感じ?)だったのですね。Cookieの設定を決してやっても同じ結果なので、HttpClientを作り直していたことが直接の原因そうです。ありがとうございます。

    キャンセル

+1

質問のコメント欄で、

クッキーではなくてトークンと言うことはないですか? 

とコメントしましたが、質問に書いてある、

http://developers.u-aizu.ac.jp/index
のapiを使っています。

を見る限り、クッキーもトークンも関係なくて、id と password の JSON 文字列を POST すれば、それらが有効であれば Response example に書いてあるような JSON 文字列が返ってくるというように読めます。

ログイン後に、ユーザーの"self"情報が得られない(ログインのみできる)
selfの情報を送った時のメッセージです。

「ログイン後」とか「selfの情報を送った」というのはどういう意味なのでしょうか?

それが分かりませんが、もし、質問に書いてある http://developers.u-aizu.ac.jp/index の通り id と password の JSON 文字列を POST 送信した結果のエラーメッセージが "This user is expired." であれば、送信した id, Password が無効ということのように読めますが。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2020/04/06 11:53

    ありがとうございます。書き方に不足部分が多くてご迷惑をかけてしまいすみません。
    上のコードでは、http://developers.u-aizu.ac.jp/api?key=judgeapi/session_POST のidとpasswordの認証はできていました(帰ってくる値がResponse example に書いてあるような JSON 文字列でした)

    今回エラーが起きてしまったのは、上のloginのPOSTを送った後にユーザーのsession infoを取得する( http://developers.u-aizu.ac.jp/api?key=judgeapi%2Fself_GET
    このGETを送信すると、[{"id":1102,"code":"INVALID_REFRESH_TOKEN_ERROR","message":"This user is expired."}]というメッセージが返されるということです。(質問ではこれをselfのデータと略していました。
    すごくわかりにくくてすみません。

    キャンセル

  • 2020/04/06 13:34

    そもそもユーザー認証の仕組みの仕様は明確になっているのでしょうか? クッキーを使っているということに間違いないですか? であれば、クッキーが送られてきていることを Fiddler などで調べてみたでしょうか?

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 87.37%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る