加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > asp.Net > 正文

asp.net – 如何使用外部登录提供程序创建刷新令牌?

发布时间:2020-12-15 23:17:58 所属栏目:asp.Net 来源:网络整理
导读:我已经通过网络搜索,找不到我的问题的解决方案.我在我的应用程序中执行OAuth.我正在使用ASP .NET Web API 2和Owin.这种情况是,一旦用户向令牌终端请求,他或她将收到一个访问令牌以及刷新令牌,以生成一个新的访问令牌.我有一个类帮助我生成刷新令牌.就这个 :
我已经通过网络搜索,找不到我的问题的解决方案.我在我的应用程序中执行OAuth.我正在使用ASP .NET Web API 2和Owin.这种情况是,一旦用户向令牌终端请求,他或她将收到一个访问令牌以及刷新令牌,以生成一个新的访问令牌.我有一个类帮助我生成刷新令牌.就这个 :
public class SimpleRefreshTokenProvider : IAuthenticationTokenProvider
    {


       private static ConcurrentDictionary<string,AuthenticationTicket> _refreshTokens = new ConcurrentDictionary<string,AuthenticationTicket>();



    public async Task CreateAsync(AuthenticationTokenCreateContext context)
        {

            var refreshTokenId = Guid.NewGuid().ToString("n");
            using (AuthRepository _repo = new AuthRepository())
            {
                var refreshTokenLifeTime = context.OwinContext.Get<string>                                    ("as:clientRefreshTokenLifeTime");
                var token = new RefreshToken() 
                { 
                    Id = Helper.GetHash(refreshTokenId),ClientId = clientid,Subject = context.Ticket.Identity.Name,IssuedUtc = DateTime.UtcNow,ExpiresUtc = DateTime.UtcNow.AddMinutes(15)
                };
                context.Ticket.Properties.IssuedUtc = token.IssuedUtc;
                context.Ticket.Properties.ExpiresUtc = token.ExpiresUtc;
                token.ProtectedTicket = context.SerializeTicket();
                var result = await _repo.AddRefreshToken(token);
                if (result)
                {        
                    context.SetToken(refreshTokenId);
                }
            }
        }

        // this method will be used to generate Access Token using the Refresh Token
        public async Task ReceiveAsync(AuthenticationTokenReceiveContext context)
        {

            string hashedTokenId = Helper.GetHash(context.Token);
            using (AuthRepository _repo = new AuthRepository())
            {
                var refreshToken = await _repo.FindRefreshToken(hashedTokenId);
                if (refreshToken != null )
                {
                    //Get protectedTicket from refreshToken class
                    context.DeserializeTicket(refreshToken.ProtectedTicket);
                    // one refresh token per user and client
                    var result = await _repo.RemoveRefreshToken(hashedTokenId);
                }
            }
        }

        public void Create(AuthenticationTokenCreateContext context)
        {
            throw new NotImplementedException();
        }

        public void Receive(AuthenticationTokenReceiveContext context)
        {
            throw new NotImplementedException();
        }
    }

现在我允许我的用户通过Facebook注册.一旦用户注册Facebook,我会生成一个访问令牌并将其交给他.我还应该生成刷新令牌吗? Onething来到我的脑海里,是生成一个长的访问令牌,如一天,那么这个用户必须再次使用Facebook登录.但是,如果我不想这样做,我可以给客户端一个刷新令牌,他可以使用它刷新生成的访问令牌,并获得一个新的.当有人注册或登录Facebook或外部时,如何创建刷新令牌并将其附加到响应?

这是我的外部注册API

public class AccountController : ApiController
    {
      [AllowAnonymous]
      [Route("RegisterExternal")]
      public async Task<IHttpActionResult> RegisterExternal(RegisterExternalBindingModel model)
      {

         if (!ModelState.IsValid)
         {
            return BadRequest(ModelState);
         }
         var accessTokenResponse = GenerateLocalAccessTokenResponse(model.UserName);
         return Ok(accessTokenResponse);
      }


    }

//私有方法来生成访问令牌

private JObject GenerateLocalAccessTokenResponse(string userName)
        {

            var tokenExpiration = TimeSpan.FromDays(1);
            ClaimsIdentity identity = new ClaimsIdentity(OAuthDefaults.AuthenticationType);
            identity.AddClaim(new Claim(ClaimTypes.Name,userName));
            identity.AddClaim(new Claim("role","user"));
            var props = new AuthenticationProperties()
            {
                IssuedUtc = DateTime.UtcNow,ExpiresUtc = DateTime.UtcNow.Add(tokenExpiration),};
            var ticket = new AuthenticationTicket(identity,props);
            var accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
            JObject tokenResponse = new JObject(
                                        new JProperty("userName",userName),new JProperty("access_token",accessToken),// Here is what I need
                                        new JProperty("resfresh_token",GetRefreshToken()),new JProperty("token_type","bearer"),new JProperty("refresh_token",refreshToken),new JProperty("expires_in",tokenExpiration.TotalSeconds.ToString()),new JProperty(".issued",ticket.Properties.IssuedUtc.ToString()),new JProperty(".expires",ticket.Properties.ExpiresUtc.ToString())
        );
            return tokenResponse;
        }

解决方法

我花了很多时间找到这个问题的答案.所以,我很乐意帮助你.

1)更改您的ExternalLogin方法.
它通常看起来像:

if (hasRegistered)
{
     Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

     ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,OAuthDefaults.AuthenticationType);
     ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,CookieAuthenticationDefaults.AuthenticationType);

     AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
     Authentication.SignIn(properties,oAuthIdentity,cookieIdentity);
}

现在,实际上有必要添加refresh_token.
方法将如下所示:

if (hasRegistered)
{
     Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);

     ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,CookieAuthenticationDefaults.AuthenticationType);

     AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);

     // ADD THIS PART
     var ticket = new AuthenticationTicket(oAuthIdentity,properties);
     var accessToken = Startup.OAuthOptions.AccessTokenFormat.Protect(ticket);

                Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext context = 
                    new Microsoft.Owin.Security.Infrastructure.AuthenticationTokenCreateContext(
                        Request.GetOwinContext(),Startup.OAuthOptions.AccessTokenFormat,ticket);

     await Startup.OAuthOptions.RefreshTokenProvider.CreateAsync(context);
     properties.Dictionary.Add("refresh_token",context.Token);

     Authentication.SignIn(properties,cookieIdentity);
}

现在将生成refrehs令牌.

2)在SimpleRefreshTokenProvider CreateAsync方法中使用基本context.SerializeTicket有一个问题.
Bit Of Technology的消息

Seems in the ReceiveAsync method,the context.DeserializeTicket is not
returning an Authentication Ticket at all in the external login case.
When I look at the context.Ticket property after that call it’s null.
Comparing that to the local login flow,the DeserializeTicket method
sets the context.Ticket property to an AuthenticationTicket. So the
mystery now is how come the DeserializeTicket behaves differently in
the two flows. The protected ticket string in the database is created
in the same CreateAsync method,differing only in that I call that
method manually in the GenerateLocalAccessTokenResponse,vs. the Owin
middlware calling it normally… And neither SerializeTicket or
DeserializeTicket throw an error…

因此,您需要使用Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer来对门票进行搜索和反序列化.
它将如下所示:

Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer serializer
                = new Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer();

token.ProtectedTicket = System.Text.Encoding.Default.GetString(serializer.Serialize(context.Ticket));

代替:

token.ProtectedTicket = context.SerializeTicket();

而对于ReceiveAsync方法:

Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer serializer = new Microsoft.Owin.Security.DataHandler.Serializer.TicketSerializer();
context.SetTicket(serializer.Deserialize(System.Text.Encoding.Default.GetBytes(refreshToken.ProtectedTicket)));

代替:

context.DeserializeTicket(refreshToken.ProtectedTicket);

3)现在,您需要将refresh_token添加到ExternalLogin方法响应.
覆盖OAuthAuthorizationServerProvider中的AuthorizationEndpointResponse.这样的事情

public override Task AuthorizationEndpointResponse(OAuthAuthorizationEndpointResponseContext context)
{
     var refreshToken = context.OwinContext.Authentication.AuthenticationResponseGrant.Properties.Dictionary["refresh_token"];
     if (!string.IsNullOrEmpty(refreshToken))
     {
          context.AdditionalResponseParameters.Add("refresh_token",refreshToken);
     }
     return base.AuthorizationEndpointResponse(context);
}

所以..这一切!现在,在调用ExternalLogin方法后,你会得到url:
https://localhost:44301/Account/ExternalLoginCallback?access_token=ACCESS_TOKEN&token_type=bearer&expires_in=300&state=STATE&refresh_token=TICKET&returnUrl=URL

我希望这有帮助)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读