There is no such thing as the best way and the answer is always it depends
, though it is very unhelpful. You can use forms authentication for example. If you web application using the web service and the web service are part of the same ASP.NET application
, the browser can seamlessly send the forms authentication ticket (cookie) for every call to the web service.
In the config file, you can have
<authorization>
<deny users="?" />
</authorization>
This will deny access to anonymous users and that will cover the web services as well. In other words, unless a user logs in and gets a valid cookie with the ticket, service cannot be used. Of course, you must HTTPS
. Otherwise, any one in the middle can get the cookie in the headers and call your service.
Finally, it is not possible to ensure no one call the web service outside of your application in an absolute sense. The above approach ensures none in the middle calls your service. But there is no way to ensure a valid user calls the service directly outside of your application because the web service caller is JavaScript and whatever security you build in JavaScript can be easily figured out by a user by looking at the script or even looking at the traffic from and to the browser. Any end user who is a bit technical, will be able to replay the requests or modify the requests and submit to your web service using valid credentials.
EDIT:-
Here are the more details you are looking for to enable FormsAuthentication.
(1) In Web.config
, under <system.web>
, make sure you have this.
<authentication mode="Forms">
<forms loginUrl="Login.aspx" defaultUrl="~/" />
</authentication>
<authorization>
<deny users="?" />
</authorization>
This will ensure all non-authenticated (anonymous) users are redirected to Login.aspx.
(2) Implement Login.aspx
with your login logic to get the user Id and password and validate them against a database or whatever. Once authentication is successful, that is, the user entered ID and password matches what you have in the database, may be in the login button click handler, set the ticket.
protected void Button1_Click(object sender, EventArgs e)
{
// Do all your login logic here
// once user ID and password entered by the user are okay, call this
string ticket = FormsAuthentication.Encrypt(
new FormsAuthenticationTicket("userId", false, 15));
HttpCookie FormsCookie = new HttpCookie(
FormsAuthentication.FormsCookieName, ticket) { HttpOnly = true };
HttpContext.Current.Response.Cookies.Add(FormsCookie);
}
(3) Add PrincipalPermissionAttribute
to the web method like this.
public class Users : System.Web.Services.WebService
{
[PrincipalPermissionAttribute(SecurityAction.Demand)]
[WebMethod]
public List<User> GetUsers()
{
// Same code as what you have now
}
}
If you now go to any page, you will be redirected to login.aspx where you will need to enter user ID and password and login. On login, the forms authentication cookie will be created and written to the response. From that point onwards, all the requests to your application will bring in the cookie (browser will do that for you). Without logging in, if you go to the web service directly, you will still be redirected to the login page. As I mentioned in my original answer, a logged in user however will still be able to access the web service directly. If JavaScript can do something, a user can do the same.
BTW, web services (asmx) is a deprecated technology.