1

一時セッションを使用すると、正常に動作します。認証サービスにログインし、パラメータなしで /auth を呼び出すと、表示名、セッション ID などが表示されます。

私がRememberMe=trueでログインすると、その呼び出しはセッション情報を正しく返します。ただし、パラメータを指定せずに /auth を呼び出すと、ServiceStack は認証されていない 401 を返します。セッション オブジェクトの IsAuthenticated プロパティは true であり、実際に存在します。私のコードはこれをチェックし、それが偽の場合、ユーザーをログインページに転送しますが、これは発生しないため、ユーザーが実際に認証されていることがわかります。

私は何も違うことをしているわけではありません。パーマネント セッションで認証し、その後 /auth を呼び出して、ログインしていることを確認するにはどうすればよいですか?

それが役立つ場合は、CustomCredentialsProvider を使用しています。

アップデート:

AppHost コード:

    public override void Configure(Funq.Container container)
    {
        //Set JSON web services to return idiomatic JSON camelCase properties
        ServiceStack.Text.JsConfig.EmitCamelCaseNames = true;

        Config.RestrictAllCookiesToDomain = ConfigurationManager.AppSettings["cookieDomain"];

        Plugins.Add(new AuthFeature(() => new CustomUserSession(),
            new IAuthProvider[] { 
                    new CustomCredentialsProvider() 
                        { SessionExpiry = 
                            TimeSpan.FromMinutes(Convert.ToDouble(ConfigurationManager.AppSettings["SessionTimeout"])) 
                        }, 
                }) //end IAuthProvider
                {
                    IncludeAssignRoleServices = false,
                    IncludeRegistrationService = false,
                    HtmlRedirect = ConfigurationManager.AppSettings["mainSiteLink"] + "Login.aspx"
                } //end AuthFeature initializers
                );//end plugins.add AuthFeature

        Plugins.Add(new PostmanFeature() { EnableSessionExport = true });// this is only for when we want the feature and it's NOT in DebugMode
        Plugins.Add(new SwaggerFeature());
        Plugins.Add(new CorsFeature(allowedOrigins: "*",
                                    allowedMethods: "GET, POST, PUT, DELETE, OPTIONS",
                                    allowedHeaders: "Content-Type, Authorization, Accept",
                                    allowCredentials: true));


        container.Register<IRedisClientsManager>
            (c => new PooledRedisClientManager(2, ConfigurationManager.AppSettings["redisIpPort"]));
        container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient());

        container.Register<ISessionFactory>(c => new SessionFactory(c.Resolve<ICacheClient>()));


        var userRep = new InMemoryAuthRepository();
        container.Register<IUserAuthRepository>(userRep);

        //Set MVC to use the same Funq IOC as ServiceStack
        ControllerBuilder.Current.SetControllerFactory(new FunqControllerFactory(container));

#if DEBUG
        Config.DebugMode = true;

        typeof(Authenticate).AddAttributes
            (
                new RestrictAttribute
                    (RequestAttributes.HttpGet | RequestAttributes.HttpPost)
            );

#else
        typeof(Authenticate).AddAttributes(new RestrictAttribute(RequestAttributes.HttpPost));
#endif

        RegisterTypedRequestFilter<Authenticate>((req, res, dto) =>
            {
                if (dto.UserName != null && dto.UserName != string.Empty
                    && dto.Password != null && dto.Password != string.Empty)
                    if(dto.RememberMe == null)
                        dto.RememberMe = false; 
            });

        RegisterTypedResponseFilter<AuthenticateResponse>((req, res, dto) =>
            {
                var appSettings = new ServiceStack.Configuration.AppSettings();
                dto.UserId = AppHostBase.Instance.TryResolve<ICacheClient>().SessionAs<CustomUserSession>().UserId.ToString();
                dto.Meta = new Dictionary<string, string>();
                dto.Meta.Add("ExpiresMinutes", appSettings.Get("SessionTimeout"));
            });
    }

    public static void Start()
    {
        Licensing.RegisterLicense(licenceKey);
        new ServiceStackAppHost().Init();
    }

最初のリクエスト ヘッダー:

https://****.com/api2/auth?username=user&password=passwordmberme=true

  • GET /api2/auth?username=user&password=password&rememberme=true HTTP/1.1
  • 受け入れる: text/html、application/xhtml+xml、/
  • Accept-Language: en-US
  • ユーザーエージェント: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) のような Gecko
  • Accept-Encoding: gzip、デフレート
  • ホスト: propel.zola360.com
  • DNT: 1
  • 接続: キープアライブ
  • Cookie: ss-pid=P2hslABCmSs7pomRqNz5; ss-opt=perm; X-UAId=

初期応答ヘッダー:

  • HTTP/1.1 200 OK
  • キャッシュ制御: プライベート
  • コンテンツタイプ: text/html
  • コンテンツ エンコーディング: gzip
  • Vary: Accept-Encoding
  • サーバー: Microsoft-IIS/7.5
  • X-Powered-By: ServiceStack/4.033 Win32NT/.NET
  • Access-Control-Allow-Origin: *
  • アクセス制御許可メソッド: GET、POST、PUT、DELETE、OPTIONS
  • Access-Control-Allow-Headers: Content-Type、Authorization、Accept
  • Access-Control-Allow-Credentials: true
  • X-AspNet バージョン: 4.0.30319
  • セット Cookie: ss-id=pojZkNAdMcEcACDREcRM; ドメイン=.zola360.com; パス=/; HttpOnly
  • セット Cookie: ss-opt=perm; ドメイン=.zola360.com; expires=Mon, 13-Nov-2034 16:11:09 GMT; - パス=/; HttpOnly
  • セット Cookie: X-UAId=; ドメイン=.zola360.com; expires=Mon, 13-Nov-2034 16:11:09 GMT; パス=/; HttpOnly
  • セット Cookie: 47=0; ドメイン=.zola360.com; パス=/
  • セット Cookie: UserId=47; ドメイン=.zola360.com; パス=/
  • X-Powered-By: ASP.NET
  • 日付: 2014 年 11 月 13 日 (木) 16:11:09 GMT
  • コンテンツの長さ: 4129

初期応答本文:

{"userId":"47","sessionId":"PKrITmRawxAtnaABCDgN","userName":"user","re​​sponseStatus":{},"meta":{"ExpiresMinutes":"360"}}

/auth 要求への後続の呼び出し:

  • GET /api2/auth HTTP/1.1
  • 受け入れる: text/html、application/xhtml+xml、/
  • Accept-Language: en-US
  • ユーザーエージェント: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) のような Gecko
  • Accept-Encoding: gzip、デフレート
  • ホスト: propel.zola360.com
  • DNT: 1
  • 接続: キープアライブ
  • クッキー: ss-pid=cvgslABCmSs6pomYdLu0; ss-opt=perm; X-UAId=; ss-id=lYWZkFAdMcZcABCDcRM; 47=0; ユーザーID=47

/auth 応答への後続の呼び出し

  • HTTP/1.1 401 認証されていません
  • キャッシュ制御: プライベート
  • コンテンツタイプ: text/html
  • 変更: 受け入れる
  • サーバー: Microsoft-IIS/7.5
  • X-Powered-By: ServiceStack/4.033 Win32NT/.NET
  • Access-Control-Allow-Origin: *
  • アクセス制御許可メソッド: GET、POST、PUT、DELETE、OPTIONS
  • Access-Control-Allow-Headers: Content-Type、Authorization、Accept
  • Access-Control-Allow-Credentials: true
  • X-AspNet バージョン: 4.0.30319
  • X-Powered-By: ASP.NET
  • 日付: 2014 年 11 月 13 日 (木) 16:11:23 GMT
  • コンテンツの長さ: 9731

/auth 本体への後続の呼び出し:

{"responseStatus":{"errorCode":"Not Authenticated","message":"Not Authenticated","stackTrace":"[Authenticate: 11/13/2014 3:27:49 PM]:\n[REQUEST: {}]\nServiceStack.HttpError: Not Authenticated\r\n ServiceStack.Auth.AuthenticateService.Post(認証リクエスト)\r\n lambda_method(Closure , Object , Object )\r\n ServiceStack.Host.ServiceRunner` 1.Execute(IRequest リクエスト、オブジェクト インスタンス、TRequest リクエスト Dto)","エラー":[]}}

更新 自分自身を認証し、他の Web サービスを呼び出す小さな Python3 スクリプトを作成しました。RememberMe=true を使用した認証の後、Cookie は期待どおりに返されます。ss-id/pid は適切に設定され、ss-opt=perm です。ヘッダー Cookie を印刷し、それを別の要求のヘッダーに貼り付けて、[Authenticate] でマークされた別のサービスを呼び出すことを考えました。うまくいきませんでした。そこで私は何かばかげたことを試して、ss-pid Cookie 値を ss-id 値に貼り付けました。出来た。

失敗したCookie文字列は次のとおりです(セッションは編集されました:)):

cookie = " ss-id=ss-ID-session-cookie ; domain=.zola360.com; path=/; HttpOnly, ss-pid=ss-PID-session-cookie ; domain=.zola360.com; expires=Tue , 14-Nov-2034 01:34:25 GMT; path=/; HttpOnly, ss-opt=perm; domain=.zola360.com; expires=Tue, 14-Nov-2034 01:34:25 GMT; path= /; HttpOnly, X-UAId=; domain=.zola360.com; expires=Tue, 14-Nov-2034 01:34:25 GMT; path=/; HttpOnly, 47=0; domain=.zola360.com; path =/、UserId=47; ドメイン=.zola360.com; パス=/"

ss-pid 値を ss-id に貼り付けるだけで機能します。

cookie = " ss-id=ss-PID-session-cookie ; domain=.zola360.com; path=/; HttpOnly, ss-pid=ss-PID-session-cookie ; domain=.zola360.com; expires=Tue , 14-Nov-2034 01:34:25 GMT; path=/; HttpOnly, ss-opt=perm; domain=.zola360.com; expires=Tue, 14-Nov-2034 01:34:25 GMT; path= /; HttpOnly, X-UAId=; domain=.zola360.com; expires=Tue, 14-Nov-2034 01:34:25 GMT; path=/; HttpOnly, 47=0; domain=.zola360.com; path =/、UserId=47; ドメイン=.zola360.com; パス=/"

そして、私が使用した Python3 スクリプト:

import httplib2 as http
import json

try:
    from urlparse import urlparse
except ImportError:
    from urllib.parse import urlparse

headers = {
    'Accept': 'application/json',
    'Content-Type': 'application/json; charset=UTF-8'
}

uri = 'https://mysite.com'
path = '/api2/auth/credentials'

target = urlparse(uri+path)
method = 'POST'
body = '{"username": "username", "password": "password", "RememberMe": "true"}'.encode()

h = http.Http()

response, content = h.request(target.geturl(), method, body, headers)

#save the cookie and use it for subsequent requests
cookie = response['set-cookie']

print(cookie)

path2 = '/api2/time/start'
target2 = urlparse(uri+path2)

headers['cookie'] = cookie

response, content = h.request(target2.geturl(), 'GET', body, headers)

# assume that content is a json reply
# parse content with the json module
data = json.loads(content.decode())

print(data)

ss-opt=perm にしても、まだ何かが ss-id の値を見ているようです。

4

1 に答える 1

0

それを使用して認証するGET /api2/auth?username=user&password=...と、永続的な Cookie が送信されますss-pid。つまり、次のようになります。

Cookie: ss-pid=P2hslABCmSs7pomRqNz5; ss-opt=perm; X-UAId=

このオプションは、永久Cookierememberme=trueに対してユーザー セッションを維持するように ServiceStack に指示します。ss-pidこのオプションはss-opt=perm、HTTP 応答がクライアントに追加するように指示するユーザー Cookie で維持されます。

Set-Cookie: ss-opt=perm; domain=.zola360.com; expires=Mon, 13-Nov-2034 16:11:09 GMT; - path=/; HttpOnly

この場合は重要ではありませんがss-id、リクエストに一時セッションが含まれていなかったため、ServiceStack はクライアントに新しいセッションを追加するように指示します。

Set-Cookie: ss-id=pojZkNAdMcEcACDREcRM; domain=.zola360.com; path=/; HttpOnly

問題は、クライアントが最初に認証した CookieGET /api2/authを再送信していない場所(つまりvs )への後続の要求にあります。ss-pidP2hslABCmSs7pomRqNz5cvgslABCmSs6pomYdLu0

Cookie: ss-pid=cvgslABCmSs6pomYdLu0; ss-opt=perm; X-UAId=; ss-id=lYWZkFAdMcZcABCDcRM; 47=0; UserId=47

ServiceStack が認識していない (つまり、セッションを維持していない) ため401 Not Authenticated、期待どおりに返されます。

Cookie を再送信するように HTTP クライアントを構成する必要があります

使用している HTTP クライアントは明確ではありませんが、通常はデフォルトの動作である Cookie を再送信するように構成する必要があります。Ajax は、永続的なss-pidCookie とss-idそのブラウザー セッションのみの一時的な Cookie の両方を送信します。たとえば、ss-idブラウザーが閉じられると一時的な Cookie は破棄され、新しい要求を行うと新しいss-idCookie が受信されます。

C# Service Clientsでは、永続的な Cookie のみを再送信するため、クライアントは次のように認証される必要がありますRememberMe = true

var client = JsonServiceClient(BaseUrl);
var authResponse = client.Send(new Authenticate
{
    provider = "credentials",
    UserName = "user",
    Password = "p@55word",
    RememberMe = true,
});

authResponse.PrintDump();

この Auth Test に見られるように、認証されると、同じ認証済みclientインスタンスを使用して、保護されたレコードに複数回アクセスできます。

for (int i = 0; i < 500; i++)
{
    var response = client.Send<SecureResponse>(new Secured { Name = "test" });
    Console.WriteLine("loop : {0}", i);
}
于 2014-11-14T03:47:59.077 に答える