OWIN Katana中间件:如果返回的声明中没有特定的角色,如何阻止用户?

时间:2017-06-06 05:32:44

标签: asp.net-mvc identityserver3 openid-connect katana owin-middleware

我成功验证了Identity Server上的用户并获取了声明(以及声明中的角色)。当我不考虑角色时一切都很好。我想限制用户,除非他有特定的角色并将他重定向到专门创建的“未授权”或“拒绝访问”页面。以下代码不会引发未经授权的例外。

var canAccessPortal = id.HasClaim(c => c.Type == "role" && c.Value == "XP");
if (!canAccessPortal)
{
    throw new UnauthorizedAccessException();
}

完整的app.UseOpenIdConnectAuthentication代码如下:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    ClientId = ClientId,
    Authority = IdServBaseUri,
    RedirectUri = ClientUri,
    PostLogoutRedirectUri = ClientUri,
    ResponseType = "code id_token token",
    Scope = "openid profile roles clef",
    TokenValidationParameters = new TokenValidationParameters
    {
        NameClaimType = "name",
        RoleClaimType = "role"
    },
    SignInAsAuthenticationType = "Cookies",

    Notifications = new OpenIdConnectAuthenticationNotifications
    {
        AuthorizationCodeReceived = async n =>
        {
            // use the code to get the access and refresh token
            var tokenClient = new TokenClient(
                TokenEndpoint,
                ClientId,
                ClientSecret);

            var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, n.RedirectUri);

            if (tokenResponse.IsError)
            {
                throw new Exception(tokenResponse.Error);
            }

            // use the access token to retrieve claims from userinfo
            var userInfoClient = new UserInfoClient(UserInfoEndpoint);

            var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);

            // create new identity
            var id = new ClaimsIdentity(n.AuthenticationTicket.Identity.AuthenticationType);
            id.AddClaims(userInfoResponse.Claims);
            id.AddClaim(new Claim("access_token", tokenResponse.AccessToken));
            id.AddClaim(new Claim("expires_at", DateTime.Now.AddSeconds(tokenResponse.ExpiresIn).ToLocalTime().ToString()));
            id.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));
            id.AddClaim(new Claim("sid", n.AuthenticationTicket.Identity.FindFirst("sid").Value));

            var canAccessPortal = id.HasClaim(c => c.Type == "role" && c.Value == "XP");
            if (!canAccessPortal)
            {
                throw new UnauthorizedAccessException();
            }

            n.AuthenticationTicket = new AuthenticationTicket(
                new ClaimsIdentity(id.Claims, n.AuthenticationTicket.Identity.AuthenticationType, "name", "role"),
                n.AuthenticationTicket.Properties);
        },

        RedirectToIdentityProvider = n =>
        {
            // if signing out, add the id_token_hint
            if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
            {
                var idTokenHint = n.OwinContext.Authentication.User.FindFirst("id_token");

                if (idTokenHint != null)
                {
                    n.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                }
            }

            return Task.FromResult(0);
        }
    }
});

web.config文件中的自定义错误节点:

<customErrors mode="On" defaultRedirect="~/account/error">
  <error statusCode="401" redirect="~/account/unauthorized" />
</customErrors>

1 个答案:

答案 0 :(得分:0)

在mvc管道中实现授权的最佳位置是实现AuthorizationAttribute。在这里,您可以完全控制请求上下文。确保您是否正在授权MVC,您应该实现System.Web.MVC .AuthorizeAttribute并实现覆盖AuthorizeCore。

    protected override bool AuthorizeCore(HttpContextBase httpContext) {

        if (!base.AuthorizeCore(httpContext)) {
            return false;
        }
        //Check roles from DB service 
        return roleservice.UserInRole && UserClaims.Count > 0;
    }

    /// <summary>
    /// Processes HTTP requests that fail authorization.
    /// </summary>
    /// <param name="filterContext">Encapsulates the information for using <see cref="T:System.Web.Mvc.AuthorizeAttribute" />. The <paramref name="filterContext" /> object contains the controller, HTTP context, request context, action result, and route data.</param>
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) {
        filterContext.Result = new RedirectResult("~/main/unauthorized");
    }