2015-06-11 21 views
7

Tôi xin lỗi trước vì đã hỏi điều này vì tôi không có kiến ​​thức về bảo mật nói chung và IdentityServer nói riêng.Thiết lập IdentityServer wtih Ứng dụng Asp.Net MVC

Tôi đang cố gắng thiết lập IdentityServer để quản lý bảo mật cho ứng dụng Asp.Net MVC.

tôi đang theo các hướng dẫn trên trang web của họ: Asp.Net MVC with IdentityServer

Tuy nhiên, tôi đang làm một cái gì đó hơi khác nhau ở chỗ tôi có một dự án riêng biệt cho Identity "Máy chủ" phần, dẫn đến file 2 Startup.cs, một cho việc áp dụng và một cho Identity server

đối với các ứng dụng, tập tin Startup.cs trông như thế này

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); 
    } 
} 

đối với máy chủ bản sắc, tập tin startup.cs là

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}\bin\Configuration\idsrv3test.pfx", AppDomain.CurrentDomain.BaseDirectory), "idsrv3test"); 
    } 
} 

Tôi cũng đang thiết lập một Authorization Manager

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(); 
     } 
    } 
} 

Vì vậy, ví dụ, nếu tôi xác định một phương pháp điều khiển mà được trang trí với các thuộc tính ResourceAuthorize, như vậy

public class HomeController : Controller 
{ 

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

Sau đó, khi lần đầu tiên tôi thử truy cập phương thức này, tôi sẽ được chuyển hướng đến trang đăng nhập mặc định.

Những gì tôi không hiểu tuy nhiên, là tại sao khi tôi đăng nhập với người sử dụng tôi đã xác định cho ứng dụng (xem dưới đây),

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") 
       } 
      } 
     }; 
    } 
} 

tôi nhận được một lỗi 403, Bearer lỗi = "insufficient_scope ".

Ai đó có thể giải thích những gì tôi đang làm sai?

Bất kỳ nỗ lực nào tiếp theo để truy cập phương thức hành động cũng sẽ trả về cùng lỗi. Dường như với tôi rằng người dùng mà tôi đã xác định có các xác nhận quyền sở hữu chính xác để có thể truy cập phương thức này. Tuy nhiên, việc kiểm tra xác nhận quyền sở hữu chỉ xảy ra một lần, khi lần đầu tiên tôi thử truy cập phương thức này. Sau khi tôi đăng nhập, tôi nhận được cookie và kiểm tra xác nhận quyền sở hữu không được thực hiện trong các lần thử tiếp theo để truy cập phương thức.

Tôi bị mất một chút và sẽ đánh giá cao một số trợ giúp trong việc xóa thông tin này.

Xin cảm ơn trước.

EDIT: đây là những scoles và các lớp client

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; 
    } 
} 

Và lớp khách hàng

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 
      } 
     }; 
    } 
} 

Tôi cũng đã tạo ra một thuộc tính lọc tùy chỉnh mà tôi sử dụng để xác định khi nào những tuyên bố kiểm tra được thực hiện .

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); 
    } 
} 

Điểm ngắt chỉ được nhấn trên yêu cầu ban đầu tới url.Trên các yêu cầu tiếp theo, điểm ngắt thuộc tính bộ lọc không bị đánh và do đó không có kiểm tra nào xảy ra. Điều này gây ngạc nhiên cho tôi vì tôi cho rằng séc phải được thực hiện mỗi khi url được yêu cầu.

+2

Bạn có thể thêm scopes.cs và clients.cs cho câu hỏi? Lỗi sufffficiet_scope có nghĩa là "Yêu cầu yêu cầu đặc quyền cao hơn cung cấp bởi mã thông báo truy cập". – rawel

+1

Xin chào, tôi đã thêm các lớp bạn yêu cầu. Có lẽ loại phạm vi là sai? – Locust5304

Trả lời

3

Bạn cần phải yêu cầu các phạm vi yêu cầu của api khi người dùng đăng nhập. 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, 
+0

Xin chào, cảm ơn câu trả lời của bạn. Tôi thực sự đã phạm sai lầm khi sao chép Phạm vi và Khách hàng. Tôi đã cập nhật bài đăng ngay bây giờ. Xin lỗi vì điều đó. – Locust5304

+0

baseballStatsApi phạm vi được yêu cầu bởi api của bạn, nhưng ứng dụng của bạn() không yêu cầu phạm vi đó, bạn có thể vui lòng kiểm tra sửa đổi Scope = "openid profile roles baseballStatsApi", – rawel

+0

Vẫn không may mắn. Tôi đã thực hiện các thay đổi bạn đã đề xuất và cập nhật bài đăng gốc để phản ánh trạng thái của mã. Tôi vẫn gặp lỗi tương tự. – Locust5304

Các vấn đề liên quan