在WCF服务中添加认证和授权

在现代的软件开发中,安全性是一个不可忽视的重要方面。对于基于Windows Communication Foundation (WCF) 的服务来说,实现认证和授权机制是保护服务不被未授权访问的关键步骤。本文将介绍如何使用面向切面编程(Aspect Oriented Programming, AOP)的概念和PostSharp工具来为WCF服务添加认证授权

创建类库项目

首先,需要创建一个新的类库项目,命名为WCFService.Extensions。这个项目将引用WCFLibrary.Shared,并被所有的服务库引用。接下来,将在这个新项目中添加一个名为ServiceMethodAspect的类。

实现切面类

在ServiceMethodAspect类中,将继承OnMethodBoundaryAspect类,并重写OnEntry、OnExit和OnException方法。这三个方法分别对应方法执行前的入口点、执行后的出口点和异常处理点。

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

在这一步,可能会发现OnMethodBoundaryAspect类未被识别。为了解决这个问题,需要通过NuGet包管理器安装PostSharp和PostSharp.Redist库,并添加对PostSharp.Aspects命名空间的引用。

获取PostSharp许可证

PostSharp需要一个有效的许可证才能在项目中使用。如果满足条件,可以从获取免费许可证。许可证的部署说明可以在找到。如果不介意在Visual Studio中安装一个工具集,可以访问,安装扩展,许可证将自动部署,就可以再次构建应用程序了。

认证授权的实现

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 BaseRequest).Username; password = (arg as BaseRequest).Password; } }

这段代码通过调用args.Arguments获取方法被调用时的参数,并在BaseRequest类型的对象中查找Username和Password属性的值。

获取响应对象

在获取了Username和Password的值之后,现在可以进行认证检查,然后是授权检查。为了访问响应对象,需要编写以下代码:

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

这段代码首先获取正在执行的方法,将其转换为System.Reflection.MethodInfo类型,以便访问方法的元数据,并最终通过ReturnType属性获取方法的返回类型。

实现认证和授权管理器

接下来,需要在WCFService.Utils项目中添加一个名为Auth的文件夹,并添加两个名为AuthenticationManager和AuthorizationManager的新类。

public class AuthenticationManager { public int? Authenticate(string username, string password, out string message) { message = null; // 在这里实现认证工作,并返回用户ID,如果认证失败则返回null。 } } public class AuthorizationManager { public bool IsAuthorized(int userId, string FullyQualifiedServiceName, string MethodName) { // 根据用户ID、服务名称和服务方法名称实现授权工作,并返回TRUE如果认证通过,否则返回FALSE。 } }

这两个类中的代码是故意留空的,以便用户可以根据自己的需要实现自己的认证和授权过程。这可能涉及到本地数据库、云数据库、JSON文件、文本文件、注册表记录等。

整合所有部分

现在已经描述了所有必要的部分,让把所有的部分整合在一起,使认证和授权过程工作起来。

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) { // 用户已认证,检查授权 AuthorizationManager authorize = new AuthorizationManager(); bool isAuthorized = authorize.IsAuthorized(userId.Value, mb.DeclaringType.FullName, mb.Name); if (isAuthorized) { // 用户也已授权使用此服务的特定方法 // 设置基础响应为OK BaseResponse response = new BaseResponse { IsException = false, IsSuccess = true, Messages = null }; // 设置执行流继续执行方法 args.FlowBehavior = FlowBehavior.Continue; // 设置返回值为BaseResponse对象 args.ReturnValue = response; } else { // 授权失败,返回适当的响应 PropertyInfo piIsSuccess = returnType.GetProperty("IsSuccess"); PropertyInfo piIsException = returnType.GetProperty("IsException"); PropertyInfo piMessages = returnType.GetProperty("Messages"); piIsSuccess.SetValue(returnObj, false); piIsException.SetValue(returnObj, false); piMessages.SetValue(returnObj, new string[] { "没有权限调用此服务方法" }); args.FlowBehavior = FlowBehavior.Return; args.ReturnValue = returnObj; } } else { // 认证失败,返回适当的响应 PropertyInfo piIsSuccess = returnType.GetProperty("IsSuccess"); PropertyInfo piIsException = returnType.GetProperty("IsException"); PropertyInfo piMessages = returnType.GetProperty("Messages"); piIsSuccess.SetValue(returnObj, false); piIsException.SetValue(returnObj, false); piMessages.SetValue(returnObj, new string[] { authenticationMessage }); args.FlowBehavior = FlowBehavior.Return; args.ReturnValue = returnObj; } }
沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485