问题
I would like to create WCF restful service for mobile application with custom authentication. First request should be login, specially client sending username, password and getting access token. Then all other requests should be check access token. Also for authentication I would like to use asp.net membership provider in other words to use Forms based authentication.
回答1:
At first, we should configure the Asp.net SQL membership Provider. Then we should use Username/password security mode so that authenticate the client with custom credential.
Please refer to the below configuration.
<connectionStrings>
<add name="SqlConn" connectionString="server=myserver;database=aspnetdb;uid=sa;password=123456;" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<membership defaultProvider="SqlMembershipProvider" userIsOnlineTimeWindow="15">
<providers>
<clear />
<add
name="SqlMembershipProvider"
type="System.Web.Security.SqlMembershipProvider"
connectionStringName="SqlConn"
applicationName="WcfService2"
enablePasswordRetrieval="false"
enablePasswordReset="false"
requiresQuestionAndAnswer="false"
requiresUniqueEmail="true"
passwordFormat="Hashed" />
</providers>
</membership>
<roleManager enabled ="true"
defaultProvider ="SqlRoleProvider" >
<providers>
<add name ="SqlRoleProvider"
type="System.Web.Security.SqlRoleProvider"
connectionStringName="SqlConn"
applicationName="WcfService2"/>
</providers>
</roleManager>
<compilation debug="true" targetFramework="4.7.2" />
<httpRuntime targetFramework="4.7.2"/>
</system.web>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding>
<security mode="Message">
<message clientCredentialType="UserName"></message>
</security>
</binding>
</wsHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior>
<serviceMetadata httpGetEnabled="true" httpsGetEnabled="true"/>
<serviceDebug includeExceptionDetailInFaults="false"/>
<serviceAuthorization principalPermissionMode="UseAspNetRoles" roleProviderName="SqlRoleProvider">
</serviceAuthorization>
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvider" membershipProviderName="SqlMembershipProvider"/>
<serviceCertificate storeLocation="LocalMachine" storeName="My" x509FindType="FindByThumbprint" findValue="974ad39ff0b86210f5e7d661e56945ad5c2d3770"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
<protocolMapping>
<add binding="wsHttpBinding" scheme="http" />
</protocolMapping>
If we use WCF to create Restful Service, we should replace the WSHttpbinding with Webhttpbinding.
Before setup the connection string, we should install the asp.net sql membership provider. it ordinarily located in the “C:\Windows\Microsoft.NET\Framework64\v4.0.30319” folder.
Aspnet_regsql.exe utility.
Here is a simple tutorial.
http://mahedee.net/asp-net-membership-step-by-step/
Here is an official example.
https://docs.microsoft.com/en-us/dotnet/framework/wcf/samples/membership-and-role-provider
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-membership-provider
https://docs.microsoft.com/en-us/dotnet/framework/wcf/feature-details/how-to-use-the-aspnet-role-provider-with-a-service
Feel free to let me know if the problem still exist.
回答2:
Here is my solution without service configuration. If you have configured asp-net membership provider in web.config.
[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
public class SPHostedWCFService
{
[OperationContract]
[WebGet(UriTemplate = "Login?username={username}&password={password}", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
public void Login(string username, string password)
{
FormsAuthenticationTicket ticket = null;
MembershipProvider membershipProvider = GetMembershipProvider();
if (membershipProvider.ValidateUser(username, password))
{
SPUser user = RunWithEP.web.EnsureUser(username);
ticket = new FormsAuthenticationTicket( 1, username, DateTime.Now, DateTime.Now.AddDays(1), true, user.ID.ToString());
}
if (ticket != null)
{
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
HttpContext.Current.Response.Cookies.Add(cookie);
}
else
{
HttpContext.Current.Response.Write("Username or password incorrect.");
}
}
[OperationContract]
[WebGet(UriTemplate = "DoWork", RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.WrappedRequest)]
[PrincipalPermission(SecurityAction.Demand, Authenticated = false)]
public string DoWork()
{
if (HttpContext.Current.Request.IsAuthenticated)
{
return "authenticated request";
}
else
{
HttpContext.Current.Response.Write("Username not authenticated.");
return "not authenticated request";
}
}
}
GetMembershipProvider() specific to may environment, specially I'm using in SharePoint.
来源:https://stackoverflow.com/questions/57378352/how-to-implement-custom-authentication-in-wcf-service