使用IRequiresSessionState,IReadOnlySessionState打破oauth2但需要设置cookie

时间:2015-08-13 18:57:47

标签: c# session cookies oauth-2.0

我有一个用C#编写的通用处理程序 - 这被称为OAuth2流程的一部分,用于通过Google验证用户。

识别出正确的用户后,我需要设置一个cookie,以便网站的其余部分可以识别用户。

问题是为了设置处理程序实现IRequiresSessionState所需的会话变量 - 当我这样做时 - 然后OAuth 2进程失败并出现以下错误。

收到的回调和客户端状态与预期值不匹配的意外OAuth授权响应

所以我可以实现OAuth或编写会话变量,但不能同时执行这两个操作。我可以让OAuth调用第一页,但然后可以在URL中看到代码(我宁愿不这样做 - 因为它为任何邪恶的人提供了破坏安全性的线索)。我可以得到一个页面来调用处理程序,返回JSON来识别用户并让页面本身设置会话变量,然后转到第一页 - 但是这个页面没有内容,还需要两个跳 - 所以如何你有一个基本上是空的HTML页面,或者设置会话而没有IRequiresSessionState打破会话。

OAuth处理程序的代码如下所示。

   public void ProcessRequest(HttpContext context)
    {
        NetworkParameters networkParameters     = null;
        NetworkParameter networkParameter       = null;
        WebServerClient consumer                = null;
        AuthorizationServerDescription server   = null;
        IAuthorizationState grantedAccess       = null;
        LoginResult loginResult                 = null;

        String code                             = String.Empty;

        String result                           = String.Empty;
        String consumerSecret                   = String.Empty;
        String consumerKey                      = String.Empty;
        String securityCookieVal                = String.Empty;
        Uri tokenEndpoint                       = null;
        Uri authorizationEndpoint               = null;

        Profile profile                         = null;
        Profile profile2                        = null;
        Profiles profiles                       = null;
        NetworkAuthorizations authorizations    = null;
        NetworkAuthorization na                 = null;

        try
        {
            loginResult             = new LoginResult();
            tokenEndpoint           = new Uri("https://accounts.google.com/o/oauth2/token");
            authorizationEndpoint   = new Uri("https://accounts.google.com/o/oauth2/auth?access_type=offline&approval_prompt=auto");

            // retrieve network parameters
            networkParameters       = new NetworkParameters(Properties.Settings.Default.DatabaseConnection);
            authorizations          = new NetworkAuthorizations(Properties.Settings.Default.DatabaseConnection);

            networkParameter        = networkParameters.Select("GOOGLE");
            code                    = context.Request["code"];
            consumerKey             = networkParameter.ClientId;
            consumerSecret          = networkParameter.ClientSecret;

            // set up request
            server                          = new AuthorizationServerDescription();
            server.AuthorizationEndpoint    = authorizationEndpoint;
            server.TokenEndpoint            = tokenEndpoint;
            server.ProtocolVersion          = ProtocolVersion.V20;

            // initialise webserver client
            consumer = new WebServerClient(server, consumerKey, consumerSecret);
            consumer.ClientCredentialApplicator = ClientCredentialApplicator.PostParameter(consumerSecret);

            // retrieve access
            grantedAccess = consumer.ProcessUserAuthorization();

            profile  = GoogleServices.GetProfile(grantedAccess.AccessToken);
            profiles = new Profiles(Properties.Settings.Default.DatabaseConnection);
            profile2 = profiles.SelectByNetworkId(profile.Network, profile.NetworkId);

            if (profile2 == null)
            {
                na = new NetworkAuthorization()
                {
                    Id              = Guid.NewGuid().ToString(),
                    AccessToken     = grantedAccess.AccessToken,
                    ExpirationDate  = (DateTime)grantedAccess.AccessTokenExpirationUtc,
                    IssueDate       = (DateTime)grantedAccess.AccessTokenIssueDateUtc,
                    RefreshToken    = grantedAccess.RefreshToken,
                    Network         = profile.Network,
                    NetworkId       = profile.NetworkId
                };

                authorizations.Insert(na); 
                profiles.Insert(profile);
            }

            loginResult.UserId = profile.NetworkId;
        }
        catch (System.Exception e)
        {

            loginResult.Status.Status   = "ERROR";
            loginResult.Status.Message  = e.Message;

        }
        finally
        { 
            context.Response.ContentType = "application/json";
            context.Response.Write(JsonConvert.SerializeObject(loginResult));
        }
    }

1 个答案:

答案 0 :(得分:0)

不是真正的答案 - 但我通过将随机生成的ID传递到网站的第一页并将其存储在用户身上来解决这个问题 - 在调用第一页时设置了cookie。

在查询字符串中发送此类信息并不十分安全,但在原型中就足够了 - 最终计划是使用Node.js,这不会成为问题。