我正在尝试为WCF休息服务实现安全性,该服务将通过网络公开以供使用。以下是要求
该服务应授权合作伙伴并检查合作伙伴是否可以访问被调用的API,并且我有多个合作伙伴调用这些restful API。
如何以集中方式为每个合作伙伴授权API?
我需要为用户执行身份验证才能执行添加,删除操作。
如何以集中方式对特定API的用户进行身份验证。
答案 0 :(得分:1)
查看Azure存储REST api安全文档here,以便了解MS如何围绕其API设计安全性。
我见过的大多数REST API都使用基于API令牌的方法,其中这些令牌沿着每个请求传递以识别调用者。
另请查看this thread
答案 1 :(得分:1)
我使用以下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
}
实现了一个自定义Beahavior来处理异常。
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();
}
}
}