服务架构安全性与可追溯性改进

在本文中,将探讨职业生涯中的一个重构项目。由于安全策略的变化,被要求重构现有的WCF服务,以提高它们的安全性和可追溯性。目标是改进现有的服务架构,而不是重写整个服务代码。为了实现这一目标,决定引入授权、认证、日志记录和验证的概念。

最初的想法是重写所有服务,但由于目前使用的服务方法多达数百个,这个想法将带来巨大的开发工作量。因此,决定使用面向方面编程(AOP)来减少开发工作。

在C#中,有几个优秀的AOP库可供使用,如Castle、AspectSharp、Aspect.NET和PostSharp。在这些库中,选择了PostSharp,因为它易于使用,文档完善,并且社区中有大量示例。

使用Microsoft SQL Server来存储数据,并使用Entity Framework进行数据访问。尽管.NET Core可能是一个更现代的方法,但为了减少开发工作,选择使用.NET Framework以保持向后兼容性。

使用代码

通常,大多数开发者会按照以下方式编写WCF服务: public interface IExampleService { int CreatePlayer(string name, DateTime dateOfBirth, int? height, int? weight, string club); Player GetPlayerById(int id); List GetAllPlayers(); List GetClubPlayers(string club); }

第一个行动是将多个输入参数更改为一个包含参数的数据契约类,并按照命名约定,将它们命名为方法名+Request。 [DataContract] public class CreatePlayerRequest { [DataMember] public string Name { get; set; } [DataMember] public DateTime DateOfBirth { get; set; } [DataMember] public int? Height { get; set; } [DataMember] public int? Weight { get; set; } [DataMember] public string Club { get; set; } }

然后为每个特定的服务方法创建响应对象,同样使用命名约定方法名+Response。 [DataContract] public class CreatePlayerResponse { [DataMember] public int PlayerId { get; set; } }

当然,可以使用一个Response对象而不是GetAllPlayerResponse和GetClubPlayersResponse对象。

接下来,创建一个名为"WCFServices.Shared"的新类库项目,并将其引用到现有服务中。创建并引用此项目后,让分别创建这两个类。 [DataContract] public class BaseRequest { [DataMember] public string Username { get; set; } [DataMember] public string Password { get; set; } }

新创建的BaseRequest类将成为所有请求对象的基类,并持有认证和授权所需的信息。类似地,BaseResponse类将成为所有响应对象的基类,并持有所有方法的响应状态信息。

在创建这些类之后,服务中的所有请求和响应类应该更新如下: [DataContract] public class CreatePlayerRequest : BaseRequest { [DataMember] public string Name { get; set; } [DataMember] public DateTime DateOfBirth { get; set; } [DataMember] public int? Height { get; set; } [DataMember] public int? Weight { get; set; } [DataMember] public string Club { get; set; } }

服务和接口将如下所示: [ServiceContract] public interface IExampleService { CreatePlayerResponse CreatePlayer(CreatePlayerRequest request); GetPlayerByIdResponse GetPlayerById(GetPlayerByIdRequest request); GetAllPlayersResponse GetAllPlayers(BaseRequest request); GetClubPlayersResponse GetClubPlayers(GetClubPlayersRequest request); }

public class ExampleService : IExampleService { public CreatePlayerResponse CreatePlayer(CreatePlayerRequest request) { try { return new CreatePlayerResponse { PlayerId = PlayerRepository.CreateNewPlayer(request.Name, request.DateOfBirth, request.Height, request.Weight, request.Club), IsException = false, IsSuccess = true, Messages = new string[] { "Operation successful" } }; } catch (Exception ex) { return new CreatePlayerResponse { IsException = true, IsSuccess = false, Messages = new string[] { ex.Message; } }; } } public GetAllPlayersResponse GetAllPlayers(BaseRequest request) { try { return new GetAllPlayersResponse { PlayerList = PlayerRepository.GetAllPlayers(), IsException = false, IsSuccess = true, Messages = new string[] { "Operation successful" } }; } catch (Exception ex) { return new GetAllPlayersResponse { IsException = true, IsSuccess = false, Messages = new string[] { ex.Message; } }; } } // I think the first two methods give enough clue about the transformation. // ... }

这是系列文章的第一部分,解释了更新服务结构的基本方法,并为下一章做准备。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485