Как реализовать аутентификацию и авторизацию в WCF Restful Service - PullRequest
3 голосов
/ 02 июня 2011

Я пытаюсь реализовать безопасность для службы отдыха WCF, которая будет доступна через сеть для потребления. Вот требования

Авторизация для сервиса и определенных API

Служба должна авторизовать партнера и проверить, имеет ли партнер доступ к вызываемому API, и у меня есть несколько партнеров, вызывающих эти релевантные API.

Как я могу централизованно авторизовать каждого из этих партнеров для API?

Аутентификация для пользователя

Мне нужно выполнить аутентификацию для пользователей, чтобы выполнить операции добавления, удаления.

Как централизованно аутентифицировать пользователей для определенных API.

Ответы [ 2 ]

1 голос
/ 22 сентября 2011

Я использовал следующий appraoch для реализации авторизации и аутентификации для остальных служб.

Использовал пользовательский атрибут, который реализует атрибут, 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      

}

Реализовано пользовательское поведение для обработки исключений.

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 для отправки кода состояния и описания в случае сбоя авторизации или аутентификации.

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();
        }
    }
}
1 голос
/ 02 июня 2011

Посмотрите документацию по безопасности API REST Azure Storage здесь , чтобы получить четкое представление о том, как MS спроектировала безопасность на основе своего API.
В большинстве REST API, которые я видел, используется подход на основе маркеров APIгде эти токены передаются по каждому запросу для идентификации абонента.Также посмотрите на эту тему

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...