且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

如何在 WCF Restful Service 中实现身份验证和授权

更新时间:2023-09-20 16:06:10

我使用以下方法来实现其余服务的授权和身份验证.

I used the following appraoch to implement the Authorization and Authentication fot the rest services.

使用了实现属性、IOOperationBehavior、IParameterInspector的自定义属性

Used the Custom Attribute which Implements the Attribute, IOperationBehavior, IParameterInspector

这是实现.

public class AuthorizationAttribute : Attribute, IOperationBehavior, IParameterInspector
{

    public SLCE.Operations Operation { get; set; }

    public bool IsAuthenticationRequired { get; set; }

    #region IOperationBehavior Members

    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters)
    {

    }

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation)
    {

    }

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation)
    {           
        dispatchOperation.ParameterInspectors.Add(this);
    }

    public void Validate(OperationDescription operationDescription)
    {

    }

    #endregion

    #region IParameterInspector Members

    public void AfterCall(string operationName, object[] outputs, object returnValue, object correlationState)
    {

    }

    public object BeforeCall(string operationName, object[] inputs)
    {
        string publicKey = WebOperationContext.Current.IncomingRequest.Headers["Authorization"];
        bool flag = AuthorizationHelper.CheckPartnerAuthorization(this.Operation, publicKey);
        if (!flag)
        {   
            LicensingValidationHelper.ThrowLicensingException(HttpStatusCode.Unauthorized, SLCE.LicensingStatus.PartnerNotAuthorized.ToString());
        }
        else if(IsAuthenticationRequired)
        {
            string authenticationKey = WebOperationContext.Current.IncomingRequest.Headers["Authentication"];
            bool isAuthenticated = AuthorizationHelper.CheckUserAuthentication(authenticationKey);

            if (!isAuthenticated)
            {
                LicensingValidationHelper.ThrowLicensingException(HttpStatusCode.Unauthorized, SLCE.LicensingStatus.UserNotAuthorized.ToString());                  
            }
        }
        return null;
    }

    #endregion      

}

实现了自定义 Beahavior 来处理异常.

Implemented a custom Beahavior to handle the exceptions.

public class LicensingBehavior : WebHttpBehavior
{

    protected override void AddServerErrorHandlers(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher)
    {
        int errorHandlerCount = endpointDispatcher.ChannelDispatcher.ErrorHandlers.Count;
        base.AddServerErrorHandlers(endpoint, endpointDispatcher);
        IErrorHandler webHttpErrorHandler = endpointDispatcher.ChannelDispatcher.ErrorHandlers[errorHandlerCount];
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.RemoveAt(errorHandlerCount);
        RestErrorHandler newHandler = new RestErrorHandler(webHttpErrorHandler,DefaultOutgoingResponseFormat);
        endpointDispatcher.ChannelDispatcher.ErrorHandlers.Add(newHandler);
    }        

}

然后实现 IErrorhandler 以在授权或身份验证失败时发送状态代码和描述.

Then implemented the IErrorhandler to send the status code and description if the Authorization or authentication fails.

public class RestErrorHandler : IErrorHandler
{
    IErrorHandler _originalErrorHandler;
    WebMessageFormat _format;
    public RestErrorHandler(IErrorHandler originalErrorHandler,WebMessageFormat format)
    {
        this._originalErrorHandler = originalErrorHandler;
        this._format = format;
    }

    public bool HandleError(Exception error)
    {
        return error is WebProtocolException;
    }

    public void ProvideFault(Exception error, MessageVersion version, ref Message fault)
    {
        WebProtocolException licensingException = error as WebProtocolException;
        if (licensingException != null)
        {

            fault = Message.CreateMessage(version, null, new ValidationErrorBodyWriter(licensingException));
            if (_format == WebMessageFormat.Json)
            {
                HttpResponseMessageProperty prop = new HttpResponseMessageProperty();
                prop.StatusCode = licensingException.StatusCode;
                prop.Headers[HttpResponseHeader.ContentType] = "application/json; charset=utf-8";
                fault.Properties.Add(HttpResponseMessageProperty.Name, prop);
                fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Json));
            }
            else if(_format == WebMessageFormat.Xml)
            {
                HttpResponseMessageProperty prop = new HttpResponseMessageProperty();
                prop.StatusCode = licensingException.StatusCode;
                prop.Headers[HttpResponseHeader.ContentType] = "application/xml; charset=utf-8";
                fault.Properties.Add(HttpResponseMessageProperty.Name, prop);
                fault.Properties.Add(WebBodyFormatMessageProperty.Name, new WebBodyFormatMessageProperty(WebContentFormat.Xml));
            }
        }
        else
        {
            this._originalErrorHandler.ProvideFault(error, version, ref fault);
        }
    }

    class ValidationErrorBodyWriter : BodyWriter
    {
        private WebProtocolException validationException;
        Encoding utf8Encoding = new UTF8Encoding(false);

        public ValidationErrorBodyWriter(WebProtocolException validationException)
            : base(true)
        {
            this.validationException = validationException;
        }

        protected override void OnWriteBodyContents(XmlDictionaryWriter writer)
        {
            writer.WriteStartElement("root");
            writer.WriteAttributeString("type", "object");

            writer.WriteStartElement("StatusCode");
            writer.WriteAttributeString("type", "string");
            writer.WriteString(this.validationException.StatusCode.ToString());
            writer.WriteEndElement();

            writer.WriteStartElement("Description");
            writer.WriteAttributeString("type", "string");
            writer.WriteString(this.validationException.StatusDescription);
            writer.WriteEndElement();

            writer.WriteEndElement();
        }
    }
}