Asp.net 向RESTful API添加安全性
我想实现两个网站,需要相互沟通。(因为其中一个站点对每个客户都有单独的部署,并且分布在许多服务器上,所以共享数据库或私下通信不是一个选项。)所以我一直在研究RESTful API 不幸的是,我遇到了很多我不熟悉的信息。一个问题是安全。我们不需要任何花哨的东西——我们不是银行或任何东西。我想我们只需要使用HTTPS和基本用户名和密码就可以了 问题:Asp.net 向RESTful API添加安全性,asp.net,asp.net-mvc,rest,asp.net-apicontroller,Asp.net,Asp.net Mvc,Rest,Asp.net Apicontroller,我想实现两个网站,需要相互沟通。(因为其中一个站点对每个客户都有单独的部署,并且分布在许多服务器上,所以共享数据库或私下通信不是一个选项。)所以我一直在研究RESTful API 不幸的是,我遇到了很多我不熟悉的信息。一个问题是安全。我们不需要任何花哨的东西——我们不是银行或任何东西。我想我们只需要使用HTTPS和基本用户名和密码就可以了 问题: 如何将用户名和密码传递给API?它们只是作为URL中的裸参数传递吗 NET是否提供了任何授权此类用户名和密码的机制,或者我只是在每次请求时手动查看密
如果您控制或对连接的双方都施加重大影响,那么客户端ssl证书是一种非常强大的方法。在这种情况下,它对我很有吸引力,因为它只需要分发一个可信的CA证书,这可以在创建客户端证书之前完成。它比任何用户名和密码都要安全得多(因为密码不需要跨越网络) 我能想到的任何其他具有身份验证的解决方案,都必须有某种数据源来验证凭据。但是x509为您解决了这个问题。我们在应用程序之间和管理证书之外都做了这项工作,它工作得非常非常好。这基本上是最安全的东西
一般来说,我对.net了解不多,但(不是lmgtfy)似乎是您正在寻找的逐步格式。如果您控制连接的双方或对其施加重大影响,则客户端ssl证书是一种非常强大的方法。在这种情况下,它对我很有吸引力,因为它只需要分发一个可信的CA证书,这可以在创建客户端证书之前完成。它比任何用户名和密码都要安全得多(因为密码不需要跨越网络) 我能想到的任何其他具有身份验证的解决方案,都必须有某种数据源来验证凭据。但是x509为您解决了这个问题。我们在应用程序之间和管理证书之外都做了这项工作,它工作得非常非常好。这基本上是最安全的东西
一般来说,我对.net了解不多,但(不是lmgtfy)似乎是您正在寻找的逐步格式。只是一个想法,它实际上取决于您所说的“用户名/密码”是什么意思。如果这意味着“授权”/“访问某个API调用”,并且您希望确保客户端被“授权”来调用您的API(只有应用程序a、B可以对API进行API调用-根据您上面的评论,这似乎就是您所寻找的): 如上面的注释所示,使用
JWT
创建授权标题。有一个很好/很简单的方法
- 这很像是一个用来签署“有效载荷”的“共享秘密”(JWT)
- “发送方”将构建
并对其进行签名(并添加到标题或您想要的任何协议中-如果您喜欢它而不是JWT
标题,它可以是
)body
- “接收器”将验证发送的
JWT
- 这包括处理/减轻“重放”——
spec有一个“expire”字段(JWT
),您也可以让库验证(或者不验证,这取决于您)exp
- 这包括处理/减轻“重放”——
Hth.只是一个想法,这实际上取决于你所说的“用户名/密码”是什么意思。如果这意味着“授权”/“访问某个API调用”,并且您希望确保客户端被“授权”来调用您的API(只有应用程序a、B可以对API进行API调用-根据您上面的评论,这似乎就是您所寻找的): 如上面的注释所示,使用
JWT
创建授权标题。有一个很好/很简单的方法
- 这很像是一个用来签署“有效载荷”的“共享秘密”(JWT)
- “发送方”将构建
并对其进行签名(并添加到标题或您想要的任何协议中-如果您喜欢它而不是JWT
标题,它可以是
)body
- “接收器”将验证发送的
JWT
- 这包括处理/减轻“重放”——
spec有一个“expire”字段(JWT
),您也可以让库验证(或者不验证,这取决于您)exp
- 这包括处理/减轻“重放”——
[IdentityBasicAuthentication] // Enable Basic authentication for this controller.
[Authorize] // Require authenticated requests.
public class HomeController : ApiController
{
public IHttpActionResult Get() { . . . }
public IHttpActionResult Post() { . . . }
}
[Authorize] // Require authenticated requests.
public class HomeController : ApiController
{
public IHttpActionResult Get() { . . . }
[IdentityBasicAuthentication] // Enable Basic authentication for this action.
public IHttpActionResult Post() { . . . }
}
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
config.Filters.Add(new IdentityBasicAuthenticationAttribute());
// Other configuration code not shown...
}
}
using System;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Principal;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Filters;
using BasicAuthentication.Results;
namespace BasicAuthentication.Filters
{
public abstract class BasicAuthenticationAttribute : Attribute, IAuthenticationFilter
{
public string Realm { get; set; }
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
if (authorization == null)
{
// No authentication was attempted (for this authentication method).
// Do not set either Principal (which would indicate success) or ErrorResult (indicating an error).
return;
}
if (authorization.Scheme != "Basic")
{
// No authentication was attempted (for this authentication method).
// Do not set either Principal (which would indicate success) or ErrorResult (indicating an error).
return;
}
if (String.IsNullOrEmpty(authorization.Parameter))
{
// Authentication was attempted but failed. Set ErrorResult to indicate an error.
context.ErrorResult = new AuthenticationFailureResult("Missing credentials", request);
return;
}
Tuple<string, string> userNameAndPasword = ExtractUserNameAndPassword(authorization.Parameter);
if (userNameAndPasword == null)
{
// Authentication was attempted but failed. Set ErrorResult to indicate an error.
context.ErrorResult = new AuthenticationFailureResult("Invalid credentials", request);
return;
}
string userName = userNameAndPasword.Item1;
string password = userNameAndPasword.Item2;
IPrincipal principal = await AuthenticateAsync(userName, password, cancellationToken);
if (principal == null)
{
// Authentication was attempted but failed. Set ErrorResult to indicate an error.
context.ErrorResult = new AuthenticationFailureResult("Invalid username or password", request);
}
else
{
// Authentication was attempted and succeeded. Set Principal to the authenticated user.
context.Principal = principal;
}
}
protected abstract Task<IPrincipal> AuthenticateAsync(string userName, string password,
CancellationToken cancellationToken);
private static Tuple<string, string> ExtractUserNameAndPassword(string authorizationParameter)
{
byte[] credentialBytes;
try
{
credentialBytes = Convert.FromBase64String(authorizationParameter);
}
catch (FormatException)
{
return null;
}
// The currently approved HTTP 1.1 specification says characters here are ISO-8859-1.
// However, the current draft updated specification for HTTP 1.1 indicates this encoding is infrequently
// used in practice and defines behavior only for ASCII.
Encoding encoding = Encoding.ASCII;
// Make a writable copy of the encoding to enable setting a decoder fallback.
encoding = (Encoding)encoding.Clone();
// Fail on invalid bytes rather than silently replacing and continuing.
encoding.DecoderFallback = DecoderFallback.ExceptionFallback;
string decodedCredentials;
try
{
decodedCredentials = encoding.GetString(credentialBytes);
}
catch (DecoderFallbackException)
{
return null;
}
if (String.IsNullOrEmpty(decodedCredentials))
{
return null;
}
int colonIndex = decodedCredentials.IndexOf(':');
if (colonIndex == -1)
{
return null;
}
string userName = decodedCredentials.Substring(0, colonIndex);
string password = decodedCredentials.Substring(colonIndex + 1);
return new Tuple<string, string>(userName, password);
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
Challenge(context);
return Task.FromResult(0);
}
private void Challenge(HttpAuthenticationChallengeContext context)
{
string parameter;
if (String.IsNullOrEmpty(Realm))
{
parameter = null;
}
else
{
// A correct implementation should verify that Realm does not contain a quote character unless properly
// escaped (precededed by a backslash that is not itself escaped).
parameter = "realm=\"" + Realm + "\"";
}
context.ChallengeWith("Basic", parameter);
}
public virtual bool AllowMultiple
{
get { return false; }
}
}
}