Asp.net mvc 无法使[Authorize(Role=";Administrator";)]属性正常工作

Asp.net mvc 无法使[Authorize(Role=";Administrator";)]属性正常工作,asp.net-mvc,asp.net-identity,owin,identityserver4,identity,Asp.net Mvc,Asp.net Identity,Owin,Identityserver4,Identity,这问题我坚持了好几天,没有找到任何解决办法 首先,我用IdentityServer4创建了一个SSO服务器,这部分工作正常,我可以进行身份验证 其次,我将Asp.Net.Identy添加到SSO服务器,以管理用户和角色,并将所有这些都添加到持久存储中。这部分也行。我创建了用户和角色,并将用户附加到角色 第三,我创建了一个APS.NET MVC web应用程序,由我的SSO服务器保护,并使用OWIN。 我使用Authorize属性保护控制器,该控制器中的一个方法需要是管理员 问题是,当我尝试访问此

这问题我坚持了好几天,没有找到任何解决办法

首先,我用IdentityServer4创建了一个SSO服务器,这部分工作正常,我可以进行身份验证

其次,我将Asp.Net.Identy添加到SSO服务器,以管理用户和角色,并将所有这些都添加到持久存储中。这部分也行。我创建了用户和角色,并将用户附加到角色

第三,我创建了一个APS.NET MVC web应用程序,由我的SSO服务器保护,并使用OWIN。 我使用Authorize属性保护控制器,该控制器中的一个方法需要是管理员

问题是,当我尝试访问此方法时,系统进入一个循环,从SSO服务器来回查询ProfileService

现在,一些代码:

将ProfileService插入SSO服务器:

using IdentityServer.Models;
using IdentityServer4.Extensions;
using IdentityServer4.Models;
using IdentityServer4.Services;
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;

namespace IdentityServer.Services
{
    public class ProfileService : IProfileService
    {
        private readonly IUserClaimsPrincipalFactory<ApplicationUser> _claimsFactory;
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly RoleManager<IdentityRole> _roleManager;

        public ProfileService(UserManager<ApplicationUser> userManager, RoleManager<IdentityRole> roleManager, IUserClaimsPrincipalFactory<ApplicationUser> claimsFactory)
        {
            _userManager = userManager;
            _claimsFactory = claimsFactory;
            _roleManager = roleManager;
        }

        public async Task GetProfileDataAsync(ProfileDataRequestContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            var principal = await _claimsFactory.CreateAsync(user);

            var claims = await _userManager.GetClaimsAsync(user);

            claims = claims.Where(claim => context.RequestedClaimTypes.Contains(claim.Type)).ToList();

            // Add custom claims in token here based on user properties or any other source
            claims.Add(new Claim("employee_id", user.EmployeeId ?? string.Empty));

            context.IssuedClaims = (List<Claim>)claims;
        }

        public async Task IsActiveAsync(IsActiveContext context)
        {
            var sub = context.Subject.GetSubjectId();
            var user = await _userManager.FindByIdAsync(sub);
            context.IsActive = user != null;
        }
    }
}
当我单击调用此方法的页面中的链接时,上下文传递到服务器,但不包含要声明的角色:

如您所见,TequestedClaimType为空

另外,当我获得我的用户时,它没有附加角色列表:

同时,角色进入Pincipal对象的标识中:

我在这里和其他网站上读了很多帖子,但到目前为止,我还没有尝试解决我的问题

欢迎任何帮助

更新1:

我稍微更改了MVC客户端配置服务器端,向客户端添加角色,如下所示: 首先,我补充说:

 public static IEnumerable<IdentityResource> GetIdentityResources()
        {
            return new List<IdentityResource>
            {
                new IdentityResources.OpenId(),
                new IdentityResources.Profile(),
                new IdentityResource("roles", new[] { "role" })
            };
        }
在我的家庭控制器中,此代码始终返回false:

    if (!User.IsInRole("Administrator"))
        throw new SecurityException("User is not an admin.");
客户端和服务器之间的调用循环:

[Authorize(Roles = "Administrator")]
public ActionResult About()
{
    ViewBag.Message = "Your application description page.";
    return View();
}

我最终通过从网络上收集不同的资源来实现它

当我与之斗争时,主要问题是startup.cs中的MVC客户端

var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");

var userInfoResponse = await client.GetUserInfoAsync( new UserInfoRequest {Address = disco.UserInfoEndpoint, Token= n.ProtocolMessage.AccessToken });

claims_to_keep.AddRange(userInfoClaims);
以及完整的内存类:

using Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using System;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Owin.Security.OpenIdConnect;
using System.Security.Claims;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.Linq;
using Microsoft.Owin.Extensions;
using Microsoft.Owin.Security.Authorization.Infrastructure;
using IdentityModel;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Net.Http;
using IdentityModel.Client;

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Pour plus d'informations sur la configuration de votre application, visitez https://go.microsoft.com/fwlink/?LinkID=316888
            app.UseAuthorization();

            app.UseCookieAuthentication(new CookieAuthenticationOptions()
            {
                AuthenticationType = "Cookies",
                ExpireTimeSpan = TimeSpan.FromSeconds(10),
                SlidingExpiration = true
            });

            var tokenHandler = new JwtSecurityTokenHandler();
            tokenHandler.InboundClaimFilter.Clear();

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {

                AuthenticationType = "oidc",
                SignInAsAuthenticationType = "Cookies",
                Authority = "https://localhost:5001", //adresse du serveur IdentityServer
                ClientId = "mvc", //nom du client au sens IdentityServer, doit être configuré dans la liste des client du fichier config.cs du serveur
                RedirectUri = "https://localhost:44354/Home", //redirection si login ok doit -être dans la liste des RefirectUris du client configuré sur le serveur
                PostLogoutRedirectUri = "https://localhost:44354/Home",
                ResponseType = "id_token token",
                Resource = "Role",
                Scope = "openid profile web_api roles",
                UseTokenLifetime = true,
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    SecurityTokenValidated = async n =>
                    {
                        var claims_to_exclude = new[]
                        {
                        "test"//"aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash"
                        };

                        List<Claim> claims_to_keep =
                            n.AuthenticationTicket.Identity.Claims.Where(x => false == claims_to_exclude.Contains(x.Type)).ToList();
                        claims_to_keep.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
                        if (n.ProtocolMessage.AccessToken != null)
                        {
                            claims_to_keep.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));

                            var client = new HttpClient();
                            var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");

                            var userInfoResponse = await client.GetUserInfoAsync( new UserInfoRequest {Address = disco.UserInfoEndpoint, Token= n.ProtocolMessage.AccessToken });

                            var userInfoClaims = userInfoResponse.Claims; // filter sub since we're already getting it from id_token

                            claims_to_keep.AddRange(userInfoClaims);
                        }

                        var ci = new ClaimsIdentity(
                            n.AuthenticationTicket.Identity.AuthenticationType);
                        ci.AddClaims(claims_to_keep);
                        n.AuthenticationTicket = new Microsoft.Owin.Security.AuthenticationTicket(
                            ci, n.AuthenticationTicket.Properties
                        );
                    },
                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                        {
                            var id_token = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
                            n.ProtocolMessage.IdTokenHint = id_token;
                        }

                        return Task.FromResult(0);
                    }
                }
            });
            app.UseStageMarker(PipelineStage.Authenticate);
        }
    }
}
使用Owin;
使用Microsoft.Owin;
使用Microsoft.Owin.Security.Cookies;
使用制度;
使用System.IdentityModel.Tokens.Jwt;
使用Microsoft.Owin.Security.OpenIdConnect;
使用System.Security.Claims;
使用Microsoft.IdentityModel.Protocols.OpenIdConnect;
使用System.Linq;
使用Microsoft.Owin.Extensions;
使用Microsoft.Owin.Security.Authorization.Infrastructure;
使用IdentityModel;
使用System.Threading.Tasks;
使用System.Collections.Generic;
使用System.Net.Http;
使用IdentityModel.Client;
[程序集:OwinStartup(typeof(WebApplication1.Startup))]
命名空间WebApplication1
{
公营创业
{
公共无效配置(IAppBuilder应用程序)
{
//在visitez的votre应用程序配置上提供更多信息https://go.microsoft.com/fwlink/?LinkID=316888
app.UseAuthorization();
app.UseCookieAuthentication(新的CookieAuthenticationOptions()
{
AuthenticationType=“Cookies”,
ExpireTimeSpan=从秒开始的时间跨度(10),
slidengexpiration=true
});
var tokenHandler=new JwtSecurityTokenHandler();
tokenHandler.InboundClaimFilter.Clear();
app.UseOpenIdConnectAuthentication(新的OpenIdConnectAuthenticationOptions
{
AuthenticationType=“oidc”,
SignInAsAuthenticationType=“Cookies”,
权威=”https://localhost:5001“,//服务器地址识别服务器”
ClientId=“mvc”//nom du client au sens IdentityServer,doitêtre configural dans la liste des client du fichier config.cs du serveur
重定向URI=”https://localhost:44354/Home“,//重定向si登录确定是否在客户端服务器配置中列出重定向
PostLogoutRedirectUri=”https://localhost:44354/Home",
ResponseType=“id\u令牌”,
Resource=“Role”,
Scope=“openid profile web\u api角色”,
UseTokenLifetime=true,
通知=新的OpenIdConnectAuthenticationNotifications
{
SecurityTokenValidated=异步n=>
{
var索赔_至_排除=新[]
{
测试“/”aud“、”iss“、”nbf“、”exp“、”nonce“、”iat“、”at_hash”
};
列出要保留的索赔=
n、 AuthenticationTicket.Identity.Claims.Where(x=>false==Claims_to_exclude.Contains(x.Type)).ToList();
claims_to_keep.Add(新的claims(“id_token”,n.ProtocolMessage.IdToken));
if(n.ProtocolMessage.AccessToken!=null)
{
claims_to_keep.Add(新的claims(“access_token”,n.ProtocolMessage.AccessToken));
var client=新的HttpClient();
var disco=await client.GetDiscoveryDocumentAsync(“https://localhost:5001");
var userInfoResponse=wait client.GetUserInfoAsync(新UserInfoRequest{Address=disco.UserInfoEndpoint,Token=n.ProtocolMessage.AccessToken});
var userInfoClaims=userInfoResponse.Claims;//筛选子项,因为我们已经从id_令牌获取了它
claims_to_keep.AddRange(userInfoClaims);
}
var ci=新的索赔实体(
n、 AuthenticationTicket.Identity.AuthenticationType);
ci.添加索赔(索赔保留);
n、 AuthenticationTicket=新的Microsoft.Owin.Security.AuthenticationTicket(
ci,n.AuthenticationTicket.Properties
);
},
RedirectToIdentityProvider=n=>
{
if(n.ProtocolMessage.RequestType==OpenIdConnectRequestType.Logout)
{
var id_token=n.OwinContext。
[Authorize(Roles = "Administrator")]
public ActionResult About()
{
    ViewBag.Message = "Your application description page.";
    return View();
}
var client = new HttpClient();
var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");

var userInfoResponse = await client.GetUserInfoAsync( new UserInfoRequest {Address = disco.UserInfoEndpoint, Token= n.ProtocolMessage.AccessToken });

claims_to_keep.AddRange(userInfoClaims);
using Owin;
using Microsoft.Owin;
using Microsoft.Owin.Security.Cookies;
using System;
using System.IdentityModel.Tokens.Jwt;
using Microsoft.Owin.Security.OpenIdConnect;
using System.Security.Claims;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using System.Linq;
using Microsoft.Owin.Extensions;
using Microsoft.Owin.Security.Authorization.Infrastructure;
using IdentityModel;
using System.Threading.Tasks;
using System.Collections.Generic;
using System.Net.Http;
using IdentityModel.Client;

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            // Pour plus d'informations sur la configuration de votre application, visitez https://go.microsoft.com/fwlink/?LinkID=316888
            app.UseAuthorization();

            app.UseCookieAuthentication(new CookieAuthenticationOptions()
            {
                AuthenticationType = "Cookies",
                ExpireTimeSpan = TimeSpan.FromSeconds(10),
                SlidingExpiration = true
            });

            var tokenHandler = new JwtSecurityTokenHandler();
            tokenHandler.InboundClaimFilter.Clear();

            app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
            {

                AuthenticationType = "oidc",
                SignInAsAuthenticationType = "Cookies",
                Authority = "https://localhost:5001", //adresse du serveur IdentityServer
                ClientId = "mvc", //nom du client au sens IdentityServer, doit être configuré dans la liste des client du fichier config.cs du serveur
                RedirectUri = "https://localhost:44354/Home", //redirection si login ok doit -être dans la liste des RefirectUris du client configuré sur le serveur
                PostLogoutRedirectUri = "https://localhost:44354/Home",
                ResponseType = "id_token token",
                Resource = "Role",
                Scope = "openid profile web_api roles",
                UseTokenLifetime = true,
                Notifications = new OpenIdConnectAuthenticationNotifications
                {
                    SecurityTokenValidated = async n =>
                    {
                        var claims_to_exclude = new[]
                        {
                        "test"//"aud", "iss", "nbf", "exp", "nonce", "iat", "at_hash"
                        };

                        List<Claim> claims_to_keep =
                            n.AuthenticationTicket.Identity.Claims.Where(x => false == claims_to_exclude.Contains(x.Type)).ToList();
                        claims_to_keep.Add(new Claim("id_token", n.ProtocolMessage.IdToken));
                        if (n.ProtocolMessage.AccessToken != null)
                        {
                            claims_to_keep.Add(new Claim("access_token", n.ProtocolMessage.AccessToken));

                            var client = new HttpClient();
                            var disco = await client.GetDiscoveryDocumentAsync("https://localhost:5001");

                            var userInfoResponse = await client.GetUserInfoAsync( new UserInfoRequest {Address = disco.UserInfoEndpoint, Token= n.ProtocolMessage.AccessToken });

                            var userInfoClaims = userInfoResponse.Claims; // filter sub since we're already getting it from id_token

                            claims_to_keep.AddRange(userInfoClaims);
                        }

                        var ci = new ClaimsIdentity(
                            n.AuthenticationTicket.Identity.AuthenticationType);
                        ci.AddClaims(claims_to_keep);
                        n.AuthenticationTicket = new Microsoft.Owin.Security.AuthenticationTicket(
                            ci, n.AuthenticationTicket.Properties
                        );
                    },
                    RedirectToIdentityProvider = n =>
                    {
                        if (n.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                        {
                            var id_token = n.OwinContext.Authentication.User.FindFirst("id_token")?.Value;
                            n.ProtocolMessage.IdTokenHint = id_token;
                        }

                        return Task.FromResult(0);
                    }
                }
            });
            app.UseStageMarker(PipelineStage.Authenticate);
        }
    }
}
RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                        ClientId = clientId,
                        Authority = authority,
                        RedirectUri = redirectUri,
                        PostLogoutRedirectUri = redirectUri,
                        Scope = OpenIdConnectScope.OpenIdProfile,
                        ResponseType = OpenIdConnectResponseType.CodeIdToken,
                        TokenValidationParameters = new TokenValidationParameters
                                                    {
                                                            ValidateIssuer = true,
                                                            ValidIssuer = $"https://login.microsoftonline.com/{tenant}/v2.0",
                                                            RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role",
                                                            NameClaimType = "name",
                                                    },
                        Notifications = new OpenIdConnectAuthenticationNotifications
                                        {
                                                AuthenticationFailed = OnAuthenticationFailed  
                                        }
                }
        );

private Task OnAuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> context)
        {
            context.HandleResponse();
            context.Response.Redirect("/?errormessage=" + context.Exception.Message);
            return Task.FromResult(0);
        }