65.9K
CodeProject 正在变化。 阅读更多。
Home

WCF 中的自定义授权

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (24投票s)

2009年3月4日

CPOL

3分钟阅读

viewsIcon

200609

downloadIcon

7067

本文将展示如何实现自定义身份验证

引言

Windows Communication Foundation (WCF) 提供了在服务中实现授权的强大功能。

本文将向您展示如何实现自定义身份验证。 只有具有 ADMIN 角色的用户才能调用 Login() 方法。

注意:本文仅侧重于检查用户的角色。 您可以通过从数据库读取来修改此代码,以检查用户的用户名、密码和角色。

服务

创建自定义 Principal

它是为了向 WCF 提供您自定义的 IPrincipal 实现。 这使您有机会在每个请求的身份验证阶段之后隐式运行代码。 为此,您必须创建自己的自定义 principal 并将其返回给 WCF 管道。 然后,自定义 principal 将可从 Thread.Cur­rentPrincipal 访问到服务代码。 自定义 principal 允许完全自定义基于角色的安全,并为服务开发人员使用公开专门的安全逻辑。

编写自定义 principal 非常简单。 只需实现 IPrincipal 接口并添加您自己的自定义功能即可。 要将 principal 与 WCF 集成,您必须将 Principal­Per­missionMode 属性在 ServiceAuthorization 元素中设置为“custom”,并提供一个负责创建 principal 并将其返回给 WCF 的授权策略。 

一个 IPrincipal 派生类必须实现一个名为 IsInRole 的方法,您可以在其中传入一个角色名称并获得一个布尔响应。 此外,principal 还引用了它所包装的 identity 类。 

class CustomPrincipal : IPrincipal
{
public bool IsInRole(string role)
    {
        EnsureRoles();

        return _roles.Contains(role);
    }

    // read Role of user from database
    protected virtual void EnsureRoles()
    {
        if (_identity.Name == "AnhDV")
            _roles = new string[1] { "ADMIN" };
        else
            _roles = new string[1] { "USER" };
    }
}

创建自定义授权策略 

授权策略只是一个实现 System.IdentityModel.Policy.IAuthorizationPolicy 接口的类。 此接口的实现必须使用一个名为 Evaluate 的方法,该方法在每个请求上被调用。 在这里,您可以进入 WCF 服务安全上下文并设置自定义 principal。 下面的代码显示了一个自定义 principal 以及授权策略及其相应的配置条目。

AuthorizationPolicy:IAuthorizationPolicy 的重要部分是 Evaluate() 方法,该方法使用声明评估的上下文,尝试获取 PrimaryIdentity。 此属性表示 WCF 在用户凭据验证期间发现的 identity。 然后,该方法将其转换为 CustomPrincipal 并将其附加到当前上下文中,从而使 principal 在当前运行的线程上可用。 

class AuthorizationPolicy : IAuthorizationPolicy
{
    Guid _id = Guid.NewGuid();

    // this method gets called after the authentication stage
    public bool Evaluate(EvaluationContext evaluationContext, ref object state)
    {
        // get the authenticated client identity
        IIdentity client = GetClientIdentity(evaluationContext);

        // set the custom principal
        evaluationContext.Properties["Principal"] = new CustomPrincipal(client);

        return true;
    }

    private IIdentity GetClientIdentity(EvaluationContext evaluationContext)
    {
        object obj;
        if (!evaluationContext.Properties.TryGetValue("Identities", out obj))
            throw new Exception("No Identity found");

        IList<IIdentity> identities = obj as IList<IIdentity>;
        if (identities == null || identities.Count <= 0)
            throw new Exception("No Identity found");

        return identities[0];
    }
} 
 <serviceAuthorization principalPermissionMode="Custom">
  <authorizationPolicies>
   <add policyType="WikiService.AuthorizationPolicy, App_Code/WikiSecurity" />
  </authorizationPolicies>
 </serviceAuthorization>  

创建自定义验证器

如果服务本身,它现在将尝试针对 Windows 用户帐户验证提供的凭据,并且由于我们正在使用自己的自定义身份验证,这将失败!

密码内容位于以下重写中,我调用我的安全模块来检查用户和密码与数据库的对比

public class CustomValidator : UserNamePasswordValidator
{
    public override void Validate(string userName, string password)
    {
        // validate arguments
        if (string.IsNullOrEmpty(userName))
            throw new ArgumentNullException("userName");
        if (string.IsNullOrEmpty(password))
            throw new ArgumentNullException("password");

        // check the user credentials from database
        //int userid = 0;
        //CheckUserNameAndPassword(userName, password, out userid);
        //if (0 == userid)
        //throw new SecurityTokenException("Unknown username or password");
    }
}

我们向服务表明我们想要自己的类 'CustomValidator',该类位于程序集 'WikiSecurity' 中,使用此配置来处理密码相关内容:   

<userNameAuthentication userNamePasswordValidationMode="Custom"
   customUserNamePasswordValidatorType="CustomValidator, App_Code/WikiSecurity" />  

创建证书 

如果您使用以下配置,则能够通过网络发送您的用户名和密码。 

注意:您需要在服务器端创建并安装合适的证书以支持此功能,这是另一个故事... 

<security mode="Message">
<message clientCredentialType="UserName"/>
</security>  

您必须打开 \Certificate Setup Application\Certificate Setup\Source Code\Certificate Setup.sln 并运行它以创建您的临时证书示例: g2-anhdv-xp.fsoft.fpt.vn

并修改您的配置: 

<serviceCertificate findValue="g2-anhdv-xp.fsoft.fpt.vn" 
	x509FindType="FindBySubjectName" />

您的服务代码:示例 WikiSecurity 类

只有具有 ADMIN 角色的用户才能调用 WikiSecurity 服务的 Login() 方法: 

[PrincipalPermission(SecurityAction.Demand, Role = "ADMIN")]
public void Login()
{

} 

客户端

然后,您可以在您的客户端代理上设置用户名和密码,如下所示

var factory = new ChannelFactory<IWikiSecurity>("*");
factory.Credentials.UserName.UserName = "AnhDV";//Do Viet Anh
factory.Credentials.UserName.Password = "anhdv";
var wikiProxy = factory.CreateChannel();
wikiProxy.Login();//-->Successful

var factory = new ChannelFactory<IWikiSecurity>("*");
factory.Credentials.UserName.UserName = "AnhDV1";//Do Viet Anh 1
factory.Credentials.UserName.Password = "anhdv";
var wikiProxy = factory.CreateChannel();
wikiProxy.Login();//Access Denied

希望这有所帮助。

享受并玩得开心。

历史

  • 2009 年 3 月 4 日:初始发布
© . All rights reserved.