2

我的令牌缺少刷新和角色属性。我正在使用 OpenIddict。该代码直到今天仍然有效,并且仍然可以在家用计算机上使用,但不能在工作中使用。

我很确定我做错了什么,但由于我比较了 startup.cs、AuthorizationController.cs 并且它们是相同的(工作和家庭),我需要一些帮助,这可能是问题的根源。

我需要为登录的用户获取角色,因为我的 Angular2 应用程序需要知道用户可以在网页上做什么。

我发送的请求:

要求

工作回应:

工作响应

家庭回应:

家庭响应

启动代码(在家用电脑上也一样):

services.AddOpenIddict<int>()
                    .AddEntityFrameworkCoreStores<AppDbContext>()
                    .AddMvcBinders()
                    .EnableTokenEndpoint("/API/authorization/token")
                    .AllowPasswordFlow()
                    .AllowRefreshTokenFlow()
                    .UseJsonWebTokens()
                    .AddEphemeralSigningKey()       //todo naj bi bil pravi certifikat, če odstranič to vrstico ne dela in vidiš error.
                    .SetAccessTokenLifetime(TimeSpan.FromMinutes(30))
                    .SetRefreshTokenLifetime(TimeSpan.FromDays(14))
                    .DisableHttpsRequirement();

控制器代码(再次:在家用电脑上相同):

public class AuthorizationController : BaseController
{
    public AuthorizationController(AppDbContext context, OpenIddictApplicationManager<OpenIddictApplication<int>> applicationManager, SignInManager<AppUser> signInManager, UserManager<AppUser> userManager) : base(context, applicationManager, signInManager, userManager)
    {
    }

    [Authorize, HttpGet("authorize")]
    public async Task<IActionResult> Authorize(OpenIdConnectRequest request)
    {
        Debug.Assert(request.IsAuthorizationRequest(),
            "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
            "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

        // Retrieve the application details from the database.
        var application = await applicationManager.FindByClientIdAsync(request.ClientId, HttpContext.RequestAborted);
        if (application == null)
        {
            return View("Error", new ErrorViewModel
            {
                Error = OpenIdConnectConstants.Errors.InvalidClient,
                ErrorDescription = "Details concerning the calling client application cannot be found in the database"
            });
        }

        // Flow the request_id to allow OpenIddict to restore
        // the original authorization request from the cache.
        return View(new AuthorizeViewModel
        {
            ApplicationName = application.DisplayName,
            RequestId = request.RequestId,
            Scope = request.Scope
        });
    }

    [HttpPost("token"), Produces("application/json")]
    public async Task<IActionResult> Exchange(OpenIdConnectRequest request)
    {
        Debug.Assert(request.IsTokenRequest(),
            "The OpenIddict binder for ASP.NET Core MVC is not registered. " +
            "Make sure services.AddOpenIddict().AddMvcBinders() is correctly called.");

        if (request.IsPasswordGrantType())
        {
            var user = await userManager.FindByNameAsync(request.Username);
            if (user == null)
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The email/password couple is invalid."
                });
            }

            // Ensure the user is allowed to sign in.
            if (!await signInManager.CanSignInAsync(user))
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The specified user is not allowed to sign in."
                });
            }

            // Reject the token request if two-factor authentication has been enabled by the user.
            if (userManager.SupportsUserTwoFactor && await userManager.GetTwoFactorEnabledAsync(user))
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The specified user is not allowed to sign in."
                });
            }

            // Ensure the user is not already locked out.
            if (userManager.SupportsUserLockout && await userManager.IsLockedOutAsync(user))
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username/password couple is invalid."
                });
            }

            // Ensure the password is valid.
            if (!await userManager.CheckPasswordAsync(user, request.Password))
            {
                if (userManager.SupportsUserLockout)
                {
                    await userManager.AccessFailedAsync(user);
                }

                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The username/password couple is invalid."
                });
            }

            if (userManager.SupportsUserLockout)
            {
                await userManager.ResetAccessFailedCountAsync(user);
            }

            // Create a new authentication ticket.
            var ticket = await CreateTicketAsync(request, user);

            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }

        else if (request.IsRefreshTokenGrantType())
        {
            // Retrieve the claims principal stored in the refresh token.
            var info = await HttpContext.Authentication.GetAuthenticateInfoAsync(
                OpenIdConnectServerDefaults.AuthenticationScheme);

            // Retrieve the user profile corresponding to the refresh token.
            var user = await userManager.GetUserAsync(info.Principal);
            if (user == null)
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The refresh token is no longer valid."
                });
            }

            // Ensure the user is still allowed to sign in.
            if (!await signInManager.CanSignInAsync(user))
            {
                return BadRequest(new OpenIdConnectResponse
                {
                    Error = OpenIdConnectConstants.Errors.InvalidGrant,
                    ErrorDescription = "The user is no longer allowed to sign in."
                });
            }

            // Create a new authentication ticket, but reuse the properties stored
            // in the refresh token, including the scopes originally granted.
            var ticket = await CreateTicketAsync(request, user, info.Properties);

            return SignIn(ticket.Principal, ticket.Properties, ticket.AuthenticationScheme);
        }

        return BadRequest(new OpenIdConnectResponse
        {
            Error = OpenIdConnectConstants.Errors.UnsupportedGrantType,
            ErrorDescription = "The specified grant type is not supported."
        });
    }

    private async Task<AuthenticationTicket> CreateTicketAsync(
        OpenIdConnectRequest request, AppUser user,
        AuthenticationProperties properties = null)
    {
        // Create a new ClaimsPrincipal containing the claims that
        // will be used to create an id_token, a token or a code.
        var principal = await signInManager.CreateUserPrincipalAsync(user);

        // Note: by default, claims are NOT automatically included in the access and identity tokens.
        // To allow OpenIddict to serialize them, you must attach them a destination, that specifies
        // whether they should be included in access tokens, in identity tokens or in both.

        foreach (var claim in principal.Claims)
        {
            // In this sample, every claim is serialized in both the access and the identity tokens.
            // In a real world application, you'd probably want to exclude confidential claims
            // or apply a claims policy based on the scopes requested by the client application.
            claim.SetDestinations(OpenIdConnectConstants.Destinations.AccessToken,
                                  OpenIdConnectConstants.Destinations.IdentityToken);
        }

        // Create a new authentication ticket holding the user identity.
        var ticket = new AuthenticationTicket(principal, properties,
            OpenIdConnectServerDefaults.AuthenticationScheme);

        if (!request.IsRefreshTokenGrantType())
        {
            // Set the list of scopes granted to the client application.
            // Note: the offline_access scope must be granted
            // to allow OpenIddict to return a refresh token.
            ticket.SetScopes(new[] {
                OpenIdConnectConstants.Scopes.OpenId,
                OpenIdConnectConstants.Scopes.Email,
                OpenIdConnectConstants.Scopes.Profile,
                OpenIdConnectConstants.Scopes.OfflineAccess,
                OpenIddictConstants.Scopes.Roles
            }.Intersect(request.GetScopes()));
        }
        ticket.SetResources("OpPISWeb");     //also in startup.cs

        return ticket;
    }
}

为了解码 id_token 我正在使用angular-jwt

return this.http.post('api/authorization/token', this.encodeObjectToParams(data), options)
    .map(res => res.json())
    .map((tokens: AuthTokenModel) =>
    {
        console.log("loged in", tokens);
        let now = new Date();
        tokens.expiration_date = new Date(now.getTime() + tokens.expires_in * 1000).getTime().toString();

        localStorage.setItem('id_token', tokens.access_token);
        localStorage.setItem('refresh_token', tokens.refresh_token);

        const profile = this.jwtHelper.decodeToken(tokens.id_token) as ProfileModel;
        const roles: string[] = typeof profile.role === "string" ? [profile.role] : profile.role;
        const userProfile: Profile = new Profile(parseInt(profile.sub), roles);
        localStorage.setItem('profile', JSON.stringify(userProfile));

        this.refreshTokens(tokens.expires_in * 1000 * 0.8);

        return profile;
    });
4

1 回答 1

2

您看到的行为是由周五引入的错误引起的。我在几分钟前修复了它,此时正在发布新的软件包。

感谢您报告它。

于 2017-02-13T10:33:57.097 回答