提高WCF服务质量(第3部分——身份验证和授权)

目录

介绍

使用代码


介绍

我们已经在前面的部分讨论如何添加验证。这部分解释了我如何向WCF服务添加身份验证和授权。

使用代码

为了向我们的服务引入身份验证和授权过程,我们将使用面向方面的编程概念,如第一章所述,我们将为此使用PostSharp

第一步,让我们创建以下新的类库项目并将其命名为WCFService.Extensions。该项目将引用WCFLibrary.Shared并将被所有服务库引用。接下来要做的是将我们的ServiceMethodAspect类添加到新的类库项目中。

添加ServiceMethodAspect类后,我们将从OnMethodBoundaryAspect类继承我们的类,我们将分别用三个重写方法OnEntryOnExitOnException来装饰我们的类。

public class ServiceMethodAspect : OnMethodBoundaryAspect
{
    public override void OnEntry(MethodExecutionArgs args)
    {
    }
    public override void OnExit(MethodExecutionArgs args)
    {
    }
    public override void OnException(MethodExecutionArgs args)
    {
    }
}

执行此操作时,您将看到该OnMethodBoundaryAspect类未被识别。因此,前往NuGet包管理器控制台并安装PostSharpPostSharp.Redist库并添加对PostSharp.Aspects命名空间的引用。

此时,您将无法再构建您的项目,因为PostSharp需要有效的许可证才能在项目中使用,而我们还没有许可证。如果满足要求,您可以从此页面获得免费许可证。此外,本页还介绍了如何部署许可证。但最简单的方法(如果您不介意在Visual Studio中安装工具集)是访问此页面,安装扩展程序,仅此而已。许可证将自动部署,您将能够再次构建您的应用程序。

现在这两种方法会做什么?顾名思义,OnEntry方法将涵盖将在方法执行之前执行的操作。在执行与您的服务相关的任何操作之前,一旦调用您的服务方法,就会触发此方法。所以这看起来是一个检查身份验证和授权的好地方。但是你会意识到我们还没有关于请求对象的任何信息。这很有意义,因为我们的切面不知道哪个方法会使用哪个参数。所以,我们应该找到一种方法来访问我们的输入参数。首先,让我们在OnEntry方法的开头编写以下代码。

base.OnEntry(args);
string username = "";
string password = "";
Arguments methodArgs = args.Arguments;
foreach (var arg in methodArgs)
{
    if (arg as BaseRequest!= null)
    {
        username = (arg as AuthenticationObject).Username;
        password = (arg as AuthenticationObject).Password;
    }
}

这段代码所做的是它通过调用args.Arguments获取方法调用的参数,并查找BaseRequest类型对象中的属性UsernamePassword以获取其值。

执行此代码后,我们现在在输入参数中拥有UsernamePassword属性的值。我认为这对于我们在第一章中所做的事情是有意义的(为每个方法创建请求类作为输入参数,并从一个基类继承所有请求类,该基类保证每个方法的请求类中具有UsernamePassword属性作为输入。之后有了必要的值,我们现在可以先检查身份验证,然后是授权,如果经过身份验证,则返回结果。

现在我们发现我们必须返回一个正确的响应,我们现在必须发现如何做。再次参考第一章,请记住我们已经更改了所有返回响应类的方法,这些响应类继承了BaseResponse类,它们分别具有boolbool string[]类型的IsExceptionIsSuccessMessages属性。要访问我们的响应对象,我们需要编写以下代码:

Type returnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
object returnObj = Activator.CreateInstance(returnType);
MethodBase mb = args.Method;

这段代码有什么作用?首先,它获取通过args.Methods正在执行的方法并将其转换为类型System.Reflection.MethodInfo以发现方法的属性并提供对方法元数据的访问,最后通过访问ReturnType属性获得方法的返回类型。现在我们准备检查身份验证和授权。所以让我们切换回我们的WCFService.Utils项目并添加一个名为Auth的文件夹,并分别添加两个名为AuthenticationManagerAuthorizationManager的新类,并将其装饰如下: 

public class AuthenticationManager
{
    public int? Authenticate(string username, string password, out string message)
    {
        message = null;
        // Do your authentication work here and return UserId if authenticated, null otherwise.
    }
}
public class AuthorizationManager
{
    public bool IsAuthorized(int userId, string FullyQualifiedServiceName, string MethodName)
    {
        // Do your authorization work here according to the UserId, ServiceName and 
        // ServiceMethod name and return TRUE if authenticated, FALSE otherwise
    }
}

AuthenticateIsAuthorized方法中的代码工作有意留白,以允许用户实现自己的身份验证和授权过程。这可能会使用本地数据库、云数据库、JSON文件、文本文件、注册表记录,以及您想要的任何内容。以防万一,请记住声明integer类型标识符来保存用户数据。根据您的实现,此类型也可能会根据您的选择而改变。

现在我们已经描述了所有必要的部分,让我们将所有部分放在一起,使身份验证和授权过程正常工作。

public override void OnEntry(MethodExecutionArgs args)
{
    base.OnEntry(args);
    string username = "";
    string password = "";
    Arguments methodArgs = args.Arguments;
    foreach (var arg in methodArgs)
    {
        if (arg as BaseRequest != null)
        {
            username = (arg as BaseRequest).Username;
            password = (arg as BaseRequest).Password;
        }
    }
    Type returnType = ((System.Reflection.MethodInfo)args.Method).ReturnType;
    object returnObj = Activator.CreateInstance(returnType);
    MethodBase mb = args.Method;
    AuthenticationManager authenticate = new AuthenticationManager();
    string authenticationMessage = null;
    int? userId = authenticate.Authenticate("", "", out authenticationMessage);
    if (userId.HasValue)
    {   // User is authenticated, check authorization
        AuthorizationManager authorize = new AuthorizationManager();
        bool isAuthorized = authorize.IsAuthorized
                            (userId.Value, mb.DeclaringType.FullName, mb.Name);
        if (isAuthorized)
        {   // User is also authorized on using this services particular method
            // Set base response as OK for this authentication and authorization.
            // Note that this value will possibly be overwritten 
            // by the service method itself, so may be skipped
            BaseResponse response = new BaseResponse
            {
                IsException = false,
                IsSuccess = true,
                Messages = null
            };
            // Set execution flow to continue to method execution
            args.FlowBehavior = FlowBehavior.Continue;
            // Set the return value as BaseResponse object
            args.ReturnValue = response;
        }
        else
        {   // Authorization failed, return proper response
            // Get IsSuccess, IsException and Messages properties of the BaseRespone object
            PropertyInfo piIsSuccess = returnType.GetProperty("IsSuccess");
            PropertyInfo piIsException = returnType.GetProperty("IsException");
            PropertyInfo piMessages = returnType.GetProperty("Messages");
            // Set proper values on BaseReponse object
            piIsSuccess.SetValue(returnObj, false);,
            piIsException.SetValue(returnObj, false);
            piMessages.SetValue(returnObj, new string[] { $"You are not authorized to call 
                       this service method ({mb.DeclaringType.FullName} - {mb.Name})" });
            // Set execution flow to return
            args.FlowBehavior = FlowBehavior.Return;
            // Set the return value as BaseResponse object
            args.ReturnValue = returnObj;
        }
    }
    else
    {   // Authentication failed, return proper response
        // Get IsSuccess, IsException and Messages properties of the BaseRespone object
        PropertyInfo piIsSuccess = returnType.GetProperty("IsSuccess");
        PropertyInfo piIsException = returnType.GetProperty("IsException");
        PropertyInfo piMessages = returnType.GetProperty("Messages");
        // Set proper values on BaseReponse object
        piIsSuccess.SetValue(returnObj, false);
        piIsException.SetValue(returnObj, false);
        piMessages.SetValue(returnObj, new string[] { authenticationMessage });
        // Set execution flow to return
        args.FlowBehavior = FlowBehavior.Return;
        // Set the return value as BaseResponse object
        args.ReturnValue = returnObj;
    }
}

这是我们系列的第三部分,解释了将身份验证和授权过程添加到我们的服务请求中。

您可以在此处​​​​​​​阅读下一部分(日志记录)。

https://www.codeproject.com/Articles/5326026/Improving-WCF-Service-Quality-Part-3-Authenticatio

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值