Настройка IdentityServer wtih Asp.Net приложение MVC

Я заранее извиняюсь за этот вопрос, поскольку у меня нет знаний о безопасности в целом и IdentityServer в частности.

Я пытаюсь настроить IdentityServer для управления безопасностью для Asp.Net приложение MVC.

Я следую учебнику на своем веб-сайте:Asp.Net MVC с IdentityServer

тем не менее, я делаю что-то немного другое в том, что у меня есть отдельный проект для части Identity "Server", которая приводит к запуску 2.cs-файлы, один для приложения и один для сервера идентификации

для приложения, автозагрузку.cs-файл выглядит так

public class Startup
{
     public void Configuration(IAppBuilder app)
     {
         AntiForgeryConfig.UniqueClaimTypeIdentifier = Constants.ClaimTypes.Subject;
         JwtSecurityTokenHandler.InboundClaimTypeMap = new Dictionary<string, string>();
         app.UseCookieAuthentication(new CookieAuthenticationOptions
         {
            AuthenticationType = "Cookies"
         });

         app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
         {
            Authority = "https://localhost:44301/identity",
            ClientId = "baseballStats",
            Scope = "openid profile roles baseballStatsApi",
            RedirectUri = "https://localhost:44300/",
            ResponseType = "id_token token",
            SignInAsAuthenticationType = "Cookies",
            UseTokenLifetime = false,
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                SecurityTokenValidated = async n =>
                {
                    var userInfoClient = new UserInfoClient(
                                 new Uri(n.Options.Authority + "/connect/userinfo"),
                                 n.ProtocolMessage.AccessToken);

                    var userInfo = await userInfoClient.GetAsync();

                    // create new identity and set name and role claim type
                    var nid = new ClaimsIdentity(
                       n.AuthenticationTicket.Identity.AuthenticationType,
                        Constants.ClaimTypes.GivenName,
                        Constants.ClaimTypes.Role);

                    userInfo.Claims.ToList().ForEach(c => nid.AddClaim(new Claim(c.Item1, c.Item2)));

                    // keep the id_token for logout
                    nid.AddClaim(new Claim("id_token", n.ProtocolMessage.IdToken));

                    // add access token for sample API
                    nid.AddClaim(new Claim("access_token", n.ProtocolMessage.AccessToken));

                    // keep track of access token expiration
                    nid.AddClaim(new Claim("expires_at", DateTimeOffset.Now.AddSeconds(int.Parse(n.ProtocolMessage.ExpiresIn)).ToString()));

                    // add some other app specific claim
                    nid.AddClaim(new Claim("app_specific", "some data"));

                    n.AuthenticationTicket = new AuthenticationTicket(
                        nid,
                        n.AuthenticationTicket.Properties);
                }
            }
         });

         app.UseResourceAuthorization(new AuthorizationManager());

         app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
         {
             Authority = "https://localhost:44301/identity",
             RequiredScopes = new[] { "baseballStatsApi"}
         });

         var config = new HttpConfiguration();
         config.MapHttpAttributeRoutes();
         app.UseWebApi(config);
     }
}

для сервера идентификации-запуск.файл CS-это

 public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.Map("/identity", idsrvApp =>
        {
            idsrvApp.UseIdentityServer(new IdentityServerOptions
            {
                SiteName = "Embedded IdentityServer",
                SigningCertificate = LoadCertificate(),

                Factory = InMemoryFactory.Create(
                    users: Users.Get(),
                    clients: Clients.Get(),
                    scopes: Scopes.Get())
            });
        });
    }

    X509Certificate2 LoadCertificate()
    {
        return new X509Certificate2(
            string.Format(@"{0}binConfigurationidsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test");
    }
}

Я также настраиваю менеджер авторизации

public class AuthorizationManager : ResourceAuthorizationManager
{
    public override Task<bool> CheckAccessAsync(ResourceAuthorizationContext context)
    {
        switch (context.Resource.First().Value)
        {                    
            case "Players":
                return CheckAuthorization(context);
            case "About":
                return CheckAuthorization(context);
            default:
                return Nok();
        }
    }

    private Task<bool> CheckAuthorization(ResourceAuthorizationContext context)
    {
        switch(context.Action.First().Value)
        {
            case "Read":
                return Eval(context.Principal.HasClaim("role", "LevelOneSubscriber"));
            default:
                return Nok();
        }
    }
}

так, например, если я определяю метод контроллера, который украшен атрибутом ResourceAuthorize, например

 public class HomeController : Controller
{

    [ResourceAuthorize("Read", "About")]
    public ActionResult About()
    {
        return View((User as ClaimsPrincipal).Claims);
    }
}

затем, когда я впервые попробую чтобы получить доступ к этому методу, я буду перенаправлен на страницу входа по умолчанию.

что я не понимаю, однако, почему при входе в систему с пользователем, которого я определил для приложения (см. ниже),

public class Users
{
    public static List<InMemoryUser> Get()
    {
        return new List<InMemoryUser>
        {
            new InMemoryUser
            {
                Username = "bob",
                Password = "secret",
                Subject = "1",

                Claims = new[]
                {
                    new Claim(Constants.ClaimTypes.GivenName, "Bob"),
                    new Claim(Constants.ClaimTypes.FamilyName, "Smith"),
                    new Claim(Constants.ClaimTypes.Role, "Geek"),
                    new Claim(Constants.ClaimTypes.Role, "LevelOneSubscriber")
                }
            }
        };
    }
}

я получаю ошибку 403, ошибку носителя= "insufficient_scope".

может ли кто-нибудь объяснить, что я делаю неправильно?

любая последующая попытка доступа к методу действия вернет ту же ошибку. Мне кажется, что пользователь, которого я определил, имеет правильные утверждения для доступа к этому методу. Однако проверка претензий происходит только один раз, когда я пытаюсь получить доступ к этому методу. После входа в систему я получаю cookie, и проверка утверждений не производится во время последующих попыток доступа к методу.

Я немного потерялся и был бы признателен за помощь в прояснении этого.

спасибо заранее.

EDIT: вот scoles и клиентские классы

public static class Scopes
{
    public static IEnumerable<Scope> Get()
    {
        var scopes = new List<Scope>
        {
            new Scope
            {
                Enabled = true,
                Name = "roles",
                Type = ScopeType.Identity,
                Claims = new List<ScopeClaim>
                {
                    new ScopeClaim("role")
                }
            },
            new Scope
            {
                Enabled = true,
                Name = "baseballStatsApi",
                Description = "Access to baseball stats API",
                Type = ScopeType.Resource,
                Claims = new List<ScopeClaim>
                {
                    new ScopeClaim("role")
                }
            }
        };

        scopes.AddRange(StandardScopes.All);

        return scopes;
    }
}

и клиент класс!--9-->

 public static class Clients
{
    public static IEnumerable<Client> Get()
    {
        return new[]
        {
            new Client 
            {
                Enabled = true,
                ClientName = "Baseball Stats Emporium",
                ClientId = "baseballStats",
                Flow = Flows.Implicit,                    

                RedirectUris = new List<string>
                {
                    "https://localhost:44300/"
                }
            },
            new Client
            {
                Enabled = true,
                ClientName = "Baseball Stats API Client",
                ClientId = "baseballStats_Api",
                ClientSecrets = new List<ClientSecret>
                {
                    new ClientSecret("secret".Sha256())
                },
                Flow = Flows.ClientCredentials
            }
        };
    }
}

Я также создал пользовательский атрибут фильтра, который я использую, чтобы определить, когда выполняется проверка утверждений.

public class CustomFilterAttribute : ResourceAuthorizeAttribute
{
     public CustomFilterAttribute(string action, params string[] resources) : base(action, resources)
    {
    }

    protected override bool CheckAccess(HttpContextBase httpContext, string action, params string[] resources)
    {
        return base.CheckAccess(httpContext, action, resources);
    }
}

точка останова попадает только на начальный запрос к url. При последующих запросах точка останова атрибута фильтра не попадает и, таким образом, проверка не происходит. Это удивительно для меня, поскольку я предполагал, что проверка должна быть сделана каждый раз, когда запрашивается url.

1 ответов


вам нужно запросить области, требуемые api, когда пользователь входит в систему. Scope = "openid profile roles baseballStatsApi"

                Authority = "https://localhost:44301/identity",

                ClientId = "baseballStats",
                Scope = "openid profile roles baseballStatsApi",
                ResponseType = "id_token token",
                RedirectUri = "https://localhost:44300/",

                SignInAsAuthenticationType = "Cookies",
                UseTokenLifetime = false,