使用单个 MembershipProvider 对多个 Web 服务后端进行身份验证有何影响?

发布于 2024-10-15 17:23:25 字数 614 浏览 2 评论 0原文

在此假设场景中,有一个 ASP.NET 4 Web 应用程序同时聚合来自多个 Web 服务的数据。 Web 服务都是相同的实现,但是是单独的实例并且彼此不知道。

在 Web 应用程序中,用户为他想要访问的每个 Web 服务提供凭据,并且身份验证过程会迭代其所有用户名/密码组合以及每个 Web 服务的 URL。 (笨重的 UI 仅用于说明......)

假设 Web 应用程序使用自定义 MembershipProvider 类中的 ValidateUser 方法进行身份验证,并且 MembershipProvider< /code> 按照惯例在 web.config 中配置。

还假设自定义 MembershipProvider 类具有一个 Url 属性,该属性随着对不同 Web 服务的每次身份验证调用而变化。

假设所有这些,您如何处理用户 1 和用户 2 同时进行身份验证的场景,但用户 1 可以访问 Web 服务 A、B 和 C,用户 2 可以访问 Web 服务 X、Y ,和Z?

凭据和 URL 是否可能会混淆,导致用户 1 可能看到用户 2 的数据,反之亦然?

In this hypothetical scenario there is an ASP.NET 4 web application that simultaneously aggregates data from multiple web services. The web services are all of the same implementation, but are separate instances and are not aware of each other.

In the web application a user provides credentials for each web service he wants access to, and the authentication process iterates through all of his user name/password combos coupled with the URL for each web service. (The clunky UI is for illustration only....)

Assume the web application uses the ValidateUser method in a custom MembershipProvider class for authentication, and the MembershipProvider is configured in web.config as per usual.

Assume also that the custom MembershipProvider class has a Url property that changes with each authentication call to the different web services.

Assuming all of that, how do you handle the scenario where User 1 and User 2 are authenticating at the same time, but User 1 has access to Web Service A, B, and C, and User 2 has access to Web Service X, Y, and Z?

Will the credentials and URLs potentially get mixed up and User 1 might see User 2's data and vice-versa?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情绪失控 2024-10-22 17:23:25

如果您打算实施自定义会员资格提供商,您会遇到很多令人头疼的问题。原因是在您的应用程序模型中,授权方案基于用户拥有的任何成员资格(针对特定服务)。

我建议您拥有自己的会员资格(针对您自己的站点)并扩展配置文件模型,以便您可以直接从用户的配置文件中检索用户有权访问的每项服务的凭据。

个人资料信息可以根据您自己的会员资格和角色提供者(特定于您的站点)与您自己的授权结合使用。在这种情况下,您可以为每个用户分配特定于每个服务的角色。

为了成功实现这一目标,为每个服务编写一个包装器,用您自己的方法(调用服务)封装服务调用。这将允许您使用 [PrincipalPermissison] 属性标记您自己的方法...并实现无缝授权。

因此,如果您的用户有权访问 Amazon Web 服务,并且在他/她的个人资料中存储了该服务的凭据,您可以拥有以下权限:

用户角色:“AmazonAccessor”

public AmazonServiceWrapper
{
    [PrincipalPermission(SecurityAction.Demand, Role = "AmazonAccessor")]
    public void DoSomething()
    {
        UserProfile profile = UserProfile.Get();
        ServiceCredential credential = (ServiceCredential)(from c in profile.ServiceCredentials where c.ServiceName = "Amazon" select c).Take(1);

        if( credential == null )
            return;

        AmazonService amazon = new AmazonService();
        amazon.ClientCredentials.UserName.UserName = credential.Username; //coming from profile
        amazon.ClientCredentials.UserName.Password = credential.Password; //coming from profile

        try{
            amazon.DoSomething(); //wrap the amazon call.
        }
        catch(Exception ex)
        {

        }
    }
}

这将使您不必兼顾会员资格和各种其他令人头疼的问题。

现在要创建您自己的配置文件,您可以执行以下操作:

[Serializable]
public class ServiceCredential
{
    public string ServiceName { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string ServiceUrl { get; set; }
}

public class UserProfile : ProfileBase
{
    public static UserProfile Get(string username)
    {
        return (UserProfile)Create(username);
    }

    public static UserProfile Get()
    {
        return (UserProfile)Create(Membership.GetUser().UserName);
    }

    [SettingsAllowAnonymous(false)]
    public List<ServiceCredential> ServiceCredentials
    {
        get
        {
            try
            {
                return base.GetPropertyValue("ServiceCredentials") as List<ServiceCredential>;
            }
            catch
            {
               return new List<ServiceCredential>();
            }
        }
        set
        {
            base.SetPropertyValue("ServiceCredentials", value);
        }
    }
}

当然还有 Web 配置:

<system.Web>
<profile 
   inherits="MyApplication.UserProfile" 
   defaultProvider="AspNetSqlProfileProvider">
   <providers>
      <add 
          name="MyProfileProvider" 
          type="System.Web.Profile.SqlProfileProvider"
          connectionStringName="MyConnectionString"
          applicationName="MyApplication" />
   </providers>
</profile>
<system.Web>

If you are going to implement a custom membership provider you will see lots of headaches down the road. The reason is that in your app model, the authorization scheme is based on whatever membership the user has (for a specific service).

I would advise to have your own membership (for your own site) and extend the profile model so that you can retrieve credentials for each service that the user has access to straight out of the user's profile.

The profile information can be used in conjunction with your own authorization based on your own membership and role providers (specific for your site). In that case you can assign each user a role specific to each service.

To successfully achieve that, for each service, write a wrapper, encapsulating service calls with your own methods (which call the service). This will allow you to mark your own methods with the [PrincipalPermissison] attribute... and achieve seemless authorization.

So if your user has access to the Amazon web service and there are credentials for that service stored in his/her profile you can have the following:

User Role: "AmazonAccessor"

public AmazonServiceWrapper
{
    [PrincipalPermission(SecurityAction.Demand, Role = "AmazonAccessor")]
    public void DoSomething()
    {
        UserProfile profile = UserProfile.Get();
        ServiceCredential credential = (ServiceCredential)(from c in profile.ServiceCredentials where c.ServiceName = "Amazon" select c).Take(1);

        if( credential == null )
            return;

        AmazonService amazon = new AmazonService();
        amazon.ClientCredentials.UserName.UserName = credential.Username; //coming from profile
        amazon.ClientCredentials.UserName.Password = credential.Password; //coming from profile

        try{
            amazon.DoSomething(); //wrap the amazon call.
        }
        catch(Exception ex)
        {

        }
    }
}

This will prevent you from having to juggle membership and all sorts of other headaches.

Now to create your own profile you can do something like this:

[Serializable]
public class ServiceCredential
{
    public string ServiceName { get; set; }
    public string Username { get; set; }
    public string Password { get; set; }
    public string ServiceUrl { get; set; }
}

public class UserProfile : ProfileBase
{
    public static UserProfile Get(string username)
    {
        return (UserProfile)Create(username);
    }

    public static UserProfile Get()
    {
        return (UserProfile)Create(Membership.GetUser().UserName);
    }

    [SettingsAllowAnonymous(false)]
    public List<ServiceCredential> ServiceCredentials
    {
        get
        {
            try
            {
                return base.GetPropertyValue("ServiceCredentials") as List<ServiceCredential>;
            }
            catch
            {
               return new List<ServiceCredential>();
            }
        }
        set
        {
            base.SetPropertyValue("ServiceCredentials", value);
        }
    }
}

And of course the Web config:

<system.Web>
<profile 
   inherits="MyApplication.UserProfile" 
   defaultProvider="AspNetSqlProfileProvider">
   <providers>
      <add 
          name="MyProfileProvider" 
          type="System.Web.Profile.SqlProfileProvider"
          connectionStringName="MyConnectionString"
          applicationName="MyApplication" />
   </providers>
</profile>
<system.Web>
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文