2017-04-12 41 views
2

我目前正在使用Web API和MVC UI设置一个新项目(最终还会有一个移动UI以及可以与同一个API通信)。IdentityServer4 - API上的用户权限

所以,我有以下计划:

  1. 用户导航到MVC UI这需要它们放到IdentityServer4服务器登录或注册
  2. IdentityServer用户,然后添加到应用程序自己数据库中的user表
  3. 权限就可以对用户进行设置,以限制他们的访问

这意味着身份的服务器就是这样,标识服务器(和我我允许人们通过谷歌等登录,而不用担心他们的角色和权限)。因此,要实现上述目标,我需要检查用户对API的权限,而不是客户端(客户端可能是任何东西 - web,电话应用程序,JavaScript客户端等等,所以我们不能依赖于处理用户权限)。

在API上,我实现了Permissionhandler和PermissionRequirement授权策略。因此,在API控制器或方法上,我可以执行如下操作:[Authorize(Policy =“CreateUser”)]。看起来我需要为每个系统授予一个策略权限。

所以在授权处理我需要:

  1. 获取当前用户的用户名
  2. 如果他们在应用程序数据库中存在,检查他们的权限和身份验证或拒绝
  3. 如果他们不这样做存在于应用程序数据库中,添加它们,然后我们可以稍后从管理面板设置他们的权限

这是很好的,直到我试图从身份s请求用户的用户名erver。我知道我需要使用UserInfoClient来做到这一点,但我不知道如何使用用户的令牌/凭据从身份服务器获取他们的声明或至少获得他们的User.Identity.Name。

现在我可以使用子ID将用户添加到应用程序数据库中,但是管理权限的人不知道该人是谁,所以我需要真正使用他们的电子邮件。

现在在MVC客户端中,我可以看到没有任何问题的User.Identity.Name,但在API中该值为空!

所以我的问题是:我如何从API中获取当前用户的Identity.Name,用户名或电子邮件?

谢谢。

回答

0

我相信你已经配置IdentityServerAuthentication的Web API类似像this -

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    ... 
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions 
    { 
     Authority = "http://UrlOfIentityServer", 
     RequireHttpsMetadata = false, 
     ApiName = "exampleapi" 
    }); 
    ... 
} 

当您进行Web服务调用,您将需要通过同令牌收到IdentityServer like this -

using (var httpClient = new HttpClient()) 
{ 
    string accessToken = await HttpContext.Authentication.GetTokenAsync("access_token"); 

    httpClient.BaseAddress = new Uri("http://UrlOfWebAPI"); 
    httpClient.DefaultRequestHeaders.Clear(); 
    httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", accessToken); 

    return await httpClient.GetStringAsync("api/clock/time"); 
} 
+0

我在我的应用程序的其他层(即其他项目中)我的授权处理,所以我没有获得那样的HttpContext。我可以访问AuthorizationHandlerContext,但不知道我可以访问HttpContext吗?我可能是错的。 – Craig

2

想想我已经破解了它。

  var mvcContext = context.Resource as Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext; 
     if (mvcContext != null) 
     { 
      // Use the UserInfo endpoint to get the user's claims 
      var discoveryClient = new DiscoveryClient("http://localhost:5000"); 
      var doc = await discoveryClient.GetAsync(); 

      var accessToken = await mvcContext.HttpContext.Authentication.GetTokenAsync("access_token"); 

      var userInfoClient = new UserInfoClient(doc.UserInfoEndpoint); 
      var response = await userInfoClient.GetAsync(accessToken); 

      var claims = response.Claims; 
     } 

这是在https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies底部详细权利,使根据微软的说法,这是正确的方式。

然而你做了这个想法,谢谢你赢了。我几个小时一直在盯着这件血腥的事。有时候你需要的只是别人说什么,什么,诅咒就坏了! :)

如果任何人有一个,我仍然可以更好地实现这一目标。

干杯

+0

不客气。 +1并感谢您的分享,所以我也学到了一些东西。 – Win

+0

我期待着做类似的事情,并且非常沮丧地发现只有RBAC的身份服务器提供'角色'声明的例子。这对我来说似乎也是错误的。应用程序应确定用户拥有什么权限,并将其与客户请求的内容进行比较。仅仅因为客户已经收到用户的同意,并不意味着该用户实际上有权执行所请求的操作。我唯一的问题就是,如果用户更改他们的电子邮件地址或其他身份证明 - 如何更新应用程序级别 – crush

+0

@crush,这是一个很好的观点,而不是我已经弄清楚的东西(我正在研究的项目不再继续)。也许这是我们不需要担心的事情。有些人对不同的服务有不同的电子邮件,所以我们应该关心他们是否在IdentityServer上更改他们的电子邮件?如果我们关心,那么我们可以设置配置文件编辑器来将相关更改传递给IdentityServer?无论如何,这些都是我最初的想法。 – Craig