I just wanted to know how to return a single entity from a wcf data service?
I want to provide a methode public User Login(string username, string password) and return the loggedin user to the user interface.
Thanks!
andi
Old question is old, but you'll want to define a Service Operation:
[WebGet]
[SingleResult]
public User GetAuthenticatedUser(string username, string password) {
//
// Fetch and return the user
// with the given parameters
//
}
However the username and password are passed in clear text via the URI. A better option would be pulling the username and password data from the Authorization header of the HTTP request, encrypting the request over the wire (SSL). A simple example could be defining a constructor for the Data Service, and in it attaching to the ProcessingRequest event:
public MyDataService() {
this.ProcessingPipeline.ProcessingRequest += (o, e) => {
//
// Do stuff with e.OperationContext.RequestHeaders["Authorization"]
// storing the result into an instance property
//
};
}
With a User GetCurrentUser() service operation that references the authorization property for the username and password, instead of accepting them as GET querystring parameters.
I think this will help you.
I assume User is your entity table.
public User Login(string username,string password)
{
Entity obj = new Entity();
User objUser = (from U in obj.User where U.username = username and U.password = password Select U).Single();
return objUser;
}
This works fine for me I hope it helps you.
Related
I'm using ASP.NET Core Identity (2.0) with all the default code. I changed the AccountController.Login method to check a legacy database and migrate users when a user is not found. Since that old database had both usernames and emails, I'm populating both fields in the newly created user.
But then, if I try to log in again with a migrated user, using the email doesn't work, as it seems the SQL request always look for WHERE u.NormalizedUserName = #__normalizedUserName_0 only.
How can I enable a single user with an email and a username that differ to log in with either their username or their email?
You have the possibility to use CheckPasswordAsync(user, password) method from UserManager: https://github.com/aspnet/Identity/blob/a273e349eea2be3a40b16e6947b2deab95f4b5b2/src/Core/UserManager.cs#L692
Right before calling that method you can fetch your user in the following manner:
var user = await _userManager.FindByNameAsync(userName) ?? await _userManager.FindByEmailAsync(userName);
Based on your current UserStore implementation you may need to adjust FindByNameAsync or FindByEmailAsync or both.
Thank you to all contributors, but I think this question deserves a more precise answer.
The default templates of ASP.NET Core Identity will always create users with both the email and username containing the same value. Then, the default login handler (either in AccountController.Login or the OnPostAsync method of the Login view) will always consume the "email" field as being the username, and call PasswordSignInAsync. Though the code seems to imply it's supporting emails, this method really only accepts a username. To add to the whole confusion, the view is making validation that you entered a valid email, but what you enter will eventually be searched in the NormalizedUserName field!
Thus, if you want to allow emails as well, as stated by Mark and Razvan, you can use _userManager.FindByEmailAsync to get the actual username of the user trying to log in, then call PasswordSignInAsync with the username.
As stated by Barry Dorrans: "No you're right. The templates end up with username and email being the same during registration, but fail to keep them in sync. There's work scheduled for 2.2 to fix this ugly mess.".
An open issue here.
You must change AccountViewModel.cs
public class LoginViewModel
{
[Required]
[Display(Name = "Логин/Email")]
//[EmailAddress]
public string Email { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Пароль")]
public string Password { get; set; }
[Display(Name = "Запомнить меня")]
public bool RememberMe { get; set; }
}
AccountController.cs
public async Task Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return View(model);
}
ApplicationUser user;
if (model.Email.Contains("#"))
user = UserManager.FindByEmail(model.Email);
else
user = UserManager.FindByName(model.Email);
var result = await SignInManager.PasswordSignInAsync(user.UserName, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresVerification:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
case SignInStatus.Failure:
default:
ModelState.AddModelError("", "Неудачная попытка входа.");
return View(model);
}
}
This is my custom user authentication setup in my global.asax file, but I am currently providing the users manually in the Configure method; Is it possible to take values from a Redis server?
For example if user exists and the password is okay, can fill with these details automatically?
Plugins.Add(new AuthFeature(()=>
new AuthUserSession(),
new IAuthProvider[]{ new BasicAuthProvider() }
));
container.Register<ICacheClient>(new MemoryCacheClient());
var userRepo = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRepo);
string hash, salt;
new SaltedHash().GetHashAndSaltString("password", out hash, out salt);
userRepo.CreateUserAuth(new UserAuth
{
Id = 1,
DisplayName = "Haluk",
Email = "hal",
UserName = "haluk",
FirstName = "haluk",
LastName = "yılmaz",
PasswordHash = hash,
Salt = salt
}, "password");
Yes you can authenticate against a Redis data source. You can either use the built in RedisAuthRepository in place of the InMemoryAuthRepository, or if you have an existing Redis data set that you want to use instead of the built-in IAuthRepository pattern, I have included a solution for that, whereby you extend the BasicAuthProvider. The first method is the most straightforward:
Use the RedisAuthRepository:
So you need to establish a connection to Redis.
Then register your authentication providers.
Register the RedisAuthRepository, which the authentication providers will check credentials against, and is compatible with the RegistrationFeature
private IRedisClientsManager redisClientsManager;
public override void Configure(Funq.Container container)
{
// Configure ServiceStack to connect to Redis
// Replace with your connection details
redisClientsManager = new PooledRedisClientManager("127.0.0.1:6379");
container.Register<IRedisClientsManager>(c => redisClientsManager);
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient()).ReusedWithin(Funq.ReuseScope.None);
// Setup the authorisation feature
Plugins.Add(new AuthFeature(()=>
new AuthUserSession(),
new IAuthProvider[]{ new BasicAuthProvider() }
));
// Use a RedisAuthRepository
var userRepo = new RedisAuthRepository(redisClientsManager);
container.Register<IUserAuthRepository>(userRepo);
// You can then register users as required using the RegistrationFeature
}
Alternatively (if you have an existing user authentication dataset in Redis)
You can do this by creating a custom authentication provider that extends the existing BasicAuthProvider.
For this code you should also make sure that your familiar with the ServiceStack.Redis client.
Extend the BasicAuthProvider:
This MyRedisBasicAuthProvider extends the existing BasicAuthProvider, and instead of performing the credentials lookup from an IUserAuthRepository as given in your example code, it makes a Redis connection and matches the username to entry in Redis.
The code is fully commented but if there is anything you wish further explained, let me know.
public class MyRedisBasicAuthProvider : BasicAuthProvider
{
// The key at which we will store the user profile. i.e user:john.smith or user:homer.simpson
// Replace this key with your format as required
public const string UserKeyFormat = "user:{0}";
MyUser CurrentUser;
// Gets an instance of a redis client
static IRedisClient GetRedisClient()
{
// Get the RedisClientsManager from the Container
var redisClientManager = HostContext.TryResolve<IRedisClientsManager>();
if(redisClientManager == null)
throw new Exception("Redis is not configured");
// Return a client
return redisClientManager.GetClient();
}
// This method is used to verify the credentials provided
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
// Get a Redis client connection
using(var redisClient = GetRedisClient())
{
// Get a typed Redis Client
var userClient = redisClient.As<MyUser>();
// Try to find a matching user in Redis
CurrentUser = userClient.GetValue(string.Format(UserKeyFormat, userName));
// Check the user exists & their password is correct (You should use a hashed password here)
return CurrentUser != null && password == CurrentUser.Password;
}
}
// This method is used to populate the session details from the user profile and other source data as required
public override IHttpResult OnAuthenticated(IServiceBase authService, IAuthSession session, IAuthTokens tokens, Dictionary<string, string> authInfo)
{
// Populate the session with the details of the current user
session.PopulateWith<IAuthSession, MyUser>(CurrentUser);
// Save the session
authService.SaveSession(session);
return null;
}
public static void AddUserToRedis(MyUser user)
{
using(var redisClient = GetRedisClient())
{
// Get a typed Redis Client
var userClient = redisClient.As<MyUser>();
// Add the user to Redis
userClient.SetEntry(string.Format(UserKeyFormat, user.Username), user);
}
}
}
In the code above I have used a class MyUser to represent the user profile that I have stored in Redis, you can of course customise this class to match your user profile requirements. So this is the basic user profile class:
public class MyUser
{
public string Username { get; set; }
public string Password { get; set; } // Replace with a hashed password
public string Email { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
Setting up ServiceStack with Redis & your custom Authentication Provider:
You will need to configure ServiceStack to use Redis and tell it to use your custom authentication provider. You do this by adding the following to your Configure method in your AppHost:
public override void Configure(Funq.Container container)
{
// Configure ServiceStack to connect to Redis
// Replace with your connection details
container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("127.0.0.1:6379"));
container.Register<ICacheClient>(c => c.Resolve<IRedisClientsManager>().GetCacheClient()).ReusedWithin(Funq.ReuseScope.None);
// Add your custom credentials provider
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new MyRedisBasicAuthProvider()
}
));
// Add some test users. (If you have an existing Redis user source, you won't need to add test users.)
MyRedisBasicAuthProvider.AddUserToRedis(new MyUser {
Username = "john.smith",
Password = "test",
Email = "john.smith#email.com",
FirstName = "John",
LastName = "Smith",
});
MyRedisBasicAuthProvider.AddUserToRedis(new MyUser {
Username = "homer.simpson",
Password = "donuts",
Email = "homer.simpsons#springfield.com",
FirstName = "Homer",
LastName = "Simpson",
});
// Your other configuration settings ...
}
Notes:
In the example I haven't used a hash password, to keep the example straightforward, but this is trivial to do. Add another field public string Salt { get; set; } to the MyUser then instead of storing the plain password on MyUser store it as a hash of the password and salt i.e. hashedPassword = HashAlgorithm(password + salt). You already have code for it:
string hash, salt;
new SaltedHash().GetHashAndSaltString("password", out hash, out salt);
So this solution will now use a Redis data source to authenticate users when a service is secured using the [Authenticate] attribute. As with the standard basic provider, the credentials are authenticated at the standard /auth/basic route.
Using the Credentials provider instead of Basic:
If you want to use a credentials provider for form posts, instead of Basic authentication you can simple replace the word Basic with Credentials in the code above.
I hope this helps.
I implemented Basic Auth for my services. Since ServiceStack's AuthFeature is strongly coupled with the session concept, I implemented a custom RequestFilter that performs stateless basic auth (credentials go in, on every request). Our auth strategy internally contemplates roles and permissions.
Besides authentication, we need to enforce authorization (e.g., user is manipulating a product that he owns). We are using FluentValidation, for all service validations.
Authorization validations include cross checking auth data with request parameters. Question is, where should I place the auth data produced in the BasicAuthRequestFilter? Should I key value pair it in cache, associating, for instance, RequestContext (or any other object that uniquely identifies the request scope) with an Authentication object?
I could just plug the AuthData in the Request Dto, which is available directly at the RequestFilter, however this would mess up our service contract design. We define dtos in a separate DLL, where only service input/output details are defined.
Any suggestions?
Thanks in advance.
I too use my own custom authentication mechanism and make custom role information available to my service. I do this by authenticating the request in a custom ServiceRunner which can then pass the information directly to my custom Service base. This ultimately means accessing information about the users permissions is exceptionally easy.
Create a custom ServiceRunner:
public class ServiceRunner<T> : ServiceStack.ServiceHost.ServiceRunner<T>
{
public ServiceRunner(IAppHost appHost, ActionContext actionContext) : base(appHost, actionContext)
{
}
public override object Execute(IRequestContext requestContext, object instance, T request)
{
// Check if the instance is of type AuthenticatedBase
var authenticatedBase = instance as AuthenticatedBase;
// If the request is not using the AuthenticatedBase, then allow it to run, as normal.
if(authenticatedBase == null)
return base.Execute(requestContext, instance, request);
/*
* Authentication required. Do you authorization check here.
* i.e.
* var authorization = requestContext.GetHeader("Authorization");
* bool authorised = ... some condition;
*/
/* You have access to your service base so if you injected the Db connection
* in you app config using IoC, then you can access the Db here.
* i.e.
* authenticatedBase.Db
*/
/*
* Not authorized?
* throw new UnauthorizedException();
*/
/*
* If authorized:
* Then simple set the details about their permissions
*/
authenticatedBase.AuthData = new AuthData { Id = 123, Roles = [], Username = "" };
// Pass back the authenticated base
return base.Execute(requestContext, authenticatedBase, request);
}
}
Configure you application to use it by adding this to your AppHost:
public override IServiceRunner<TRequest> CreateServiceRunner<TRequest>(ActionContext actionContext)
{
return new ServiceRunner<TRequest>(this, actionContext);
}
Create a custom class to hold your auth data i.e. the user session information, such as:
public class AuthData
{
public int Id { get; set; }
public string Username { get; set; }
public int[] Roles { get; set; }
...
}
Then create a custom service base
public class AuthenticatedBase : Service
{
public AuthData AuthData { get; set; }
}
To then use the AuthData in the service is simply a case of extending AuthenticatedBase.
public class CustomerHandler : AuthenticatedBase
{
public object Get(ListCustomers request)
{
// You can access the AuthData now in the handler
var roles = AuthData.Role; // Check they have the role required to list customers
...
}
}
You are probably wondering why go to all the trouble of using the ServiceRunner over a RequestFilter but the main advantage is it gives direct access to the instance of the Service base, which isn't available to a RequestFilter.
The RequestFilters are run before the Service base is instantiated, so you can't populate it from there. See order of operations for more information.
By having access to the ServiceBase we can populate values (in this case AuthData) and we have access to our injected dependancies such as the database connection.
I hope you find this useful. You should be able to copy most of your existing RequestFilter into the service runner. If you need any further help with this just let me know.
Update to support Attributes:
Since you are unable to avoid using the attribute method to handle your authentication needs you can still use this method:
Continue doing your authentication and access filtering the way you were before.
In your existing authentication mechanism use req.Items.Add to set the AuthData i.e. Where req is your request object
req.Items.Add("AuthData", new AuthData { Username = "", Roles = [] ... });
Then access your AuthData item in your service base:
public class AuthenticatedBase : Service
{
public AuthData AuthData
{
get { return base.Request.Items["AuthData"] as AuthData; }
}
}
I am working on an MVC site that has some pages that need authentication and others that don't. This is determined using the Authorize and AllowAnonymous attributes in a pretty standard way. If they try to access something restricted they get redirected to the login page.
I'm now wanting to add the functionality to automatically log them in using an encrypted token passed in the querystring (the link will be in emails sent out). So the workflow I want now is that if a request goes to a page that is restricted and there is a login token in the querystring I want it to use that token to log in. If it logs in successfully then I want it to run the original page requested with the new logged in context. If it fails to log in then it will redirect to a custom error page.
My question is where would I need to insert this logic into the site?
I have seen some suggestions on subclassing the Authorize attribute and overriding some of the methods but I'm not 100% sure how to go about this (eg what I would override and what I'd do in those overridden methods.
I've also had a look at putting the logic at a controller level but I am led to understand that the authorize attribute would redirect it away from the controller before any code in the controller itself was run.
It would be better to write a custom authorization attribute that will entirely replace the default functionality and check for the query string parameter and if present, decrypt it and authenticate the user. If you are using FormsAuthentication that would be to call the FormsAuthentication.SetAuthCookie method. Something along the lines of:
public class TokenAuthorizeAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
string token = filterContext.HttpContext.Request["token"];
IPrincipal user = this.GetUserFromToken(token);
if (user == null)
{
this.HandleUnAuthorizedRequest(filterContext);
}
else
{
FormsAuthentication.SetAuthCookie(user.Identity.Name, false);
filterContext.HttpContext.User = user;
}
}
private IPrincipal GetUserFromToken(string token)
{
// Here you could put your custom logic to decrypt the token and
// extract the associated user from it
throw new NotImplementedException();
}
private void HandleUnAuthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new ViewResult
{
ViewName = "~/Views/Shared/CustomError.cshtml",
};
}
}
and then you could decorate your action with this attribute:
[TokenAuthorize]
public ActionResult ProcessEmail(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
return RedirectToAction("Index", "Home");
}
NOTE: I have many questions littered in the code comments below. I need answers to those as well.
I have read (among many others) the following articles:
http://blogs.msdn.com/b/hongmeig1/archive/2012/05/11/how-to-write-a-custom-parameter-binding-to-construct-an-object-either-from-body-or-from-uri-s-query.aspx
http://blogs.msdn.com/b/jmstall/archive/2012/05/11/webapi-parameter-binding-under-the-hood.aspx
I would like for my web api to have authentication sent in the header using the Authorization header. I would like this header to be populated into a c# class called AuthenticationToken. Then when I am doing parameter binding I would like to retreive this previously created AuthenticationToken object and pass it on to my controller action. For example, if I have the following controller
public class MyServiceController : ApiController {
readonly ISecurityService _security;
readonly IMyService _myService;
// constructor values are injected
public MyServiceController(ISecurityService security, IMyService myService) {
_security = security;
_myService = myService;
}
public SomeData GetASpecificItem(AuthenticationToken token, int id) {
if (_security.IsAuthorized(token, Permissions.Read)) {
return myService.DoStuffToGetSomeData(token);
} else {
var msg = new HttpResponseMessage(HttpStatusCode.Forbidden);
throw new HttpResponseException(msg);
}
}
}
and the following parameter binding class
public class AuthenticationTokenParameterBinding
: HttpParameterBinding { // do I need to inherit from a different class?
public override Task ExecuteBindingAsync(ModelMetadataProvider metadataProvider,
HttpActionContext actionContext,
CancellationToken cancellationToken) {
try {
AuthenticationToken token; // UPDATED: how can i get this from the data
// available from inside this method?
SetValue(actionContext, token);
// is this the correct task to return on successfull parameter binding?
return base.ExecuteBindingAsyn(metadataProvider, actionContext, cancellationToken);
} catch {
return Task<HttpResponseMessage>.Factory.StartNew(() => {
var hpm = new HttpResponseMessage(HttpStatusCode.Unauthorized);
hpm.Headers.Add("WWW-Authenticate","MyCustomScheme");
return hpm;
});
}
}
}
If these two are implemented correctly, then the controller will automatically get the AuthenticationToken instance that was created during authorization.
I do not know where to authenticate ahead of this process. Nor do I know how to pass an object between authentication and authorization.
UPDATE:
I can't use a custom AuthorizeAttribute because authorization may be against an object:
public SaveResponse Save(AuthenticationToken user, SomeObjectThatNeedsToBeSaved obj) {
// NOTE: permissions are checked between the object and the user, not a role
if (_security.IsAuthorized(user, obj, Permission.Modify, Permission.Create)) {
// NOTE: other permissions we don't know about may need to be checked in the service call
return new SaveResponse {
Success = ISomeService.Save(user, obj); // bool return value
}
} else {
// return 403 Forbidden }
}
I need to pass the token to the controller action, but I also need to authenticate the token before it gets passed to the controller. Since all of this is not necessarily role based, I don't see how I can authenticate from inside of a custom AuthorizeAttribute
I have used a custom AuthorizeAttribute to handle both authentication and authorization for Web API. This attribute works as a filter and will process the request before it gets to your Web API method. In the overridden OnAuthorize method you can return HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized) if authentication fails and HttpResponseMessage(System.Net.HttpStatusCode.Forbidden) if authorization fails so that the client can distinguish between both types of errors. In addition to the custom AuthorizeAttribute I implemented a custom MembershipProvider and RoleProvider to handle my specific security requirements and custom database schema.
I use basic authentication to pass the credentials for authorization. This puts the credentials in the header. To do this is pretty straight forward by using the beforeSend event handler of the JQuery ajax function. Here is an example of how to do this.
getAuthorizationHeader = function (username, password) {
var authType;
var up = $.base64.encode(username + ":" + password);
authType = "Basic " + up;
};
return authType;
};
$.ajax({
url: _url,
data: _data,
type: _type,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", getAuthorizationHeader(username, password));
},
success: ajaxSuccessHandler,
error: ajaxErrHandler
});
This encodes the username/password that is sent in the header. Note that this is not enough security to rely on just the encoding as it is easy to decode. You still want to use HTTPS/SSL to make sure the information sent over the wire is secure.
On the Web API side you can make a custom AuthorizeAttribute that gets the credentials from the header, decodes them, and performs your authorization process. There is a separate AuthorizeAttribute used by the Web API as opposed to the controller. Be sure to use System.Web.Http.AuthorizeAttribute as your base class when creating your custom AuthorizeAttribute. They have different behaviors. The one for the controller will want to redirect to the logon page whereas the one for the Web API returns an HTTP code indicating success or failure. I return an HTTP code of Forbidden if authorization fails to distinguish a failure due to authorization as opposed to authentication so the client can react accordingly.
Here is an example method for getting the credentials from the header that can be used in the custom AuthorizeAttribute.
private bool GetUserNameAndPassword(HttpActionContext actionContext, out string username, out string password)
{
bool gotIt = false;
username = string.Empty;
password = string.Empty;
IEnumerable<string> headerVals;
if (actionContext.Request.Headers.TryGetValues("Authorization", out headerVals))
{
try
{
string authHeader = headerVals.FirstOrDefault();
char[] delims = { ' ' };
string[] authHeaderTokens = authHeader.Split(new char[] { ' ' });
if (authHeaderTokens[0].Contains("Basic"))
{
string decodedStr = SecurityHelper.DecodeFrom64(authHeaderTokens[1]);
string[] unpw = decodedStr.Split(new char[] { ':' });
username = unpw[0];
password = unpw[1];
}
gotIt = true;
}
catch { gotIt = false; }
}
return gotIt;
}
And here is the code for decoding the header data that is used in this method.
public static string DecodeFrom64(string encodedData)
{
byte[] encodedDataAsBytes
= System.Convert.FromBase64String(encodedData);
string returnValue =
System.Text.Encoding.ASCII.GetString(encodedDataAsBytes);
return returnValue;
}
Once you have the username and password you can perform your authorization process and return the appropriate HTTP code to the client for handling.
You could perform the a similar process with your custom token, or you can leverage the cookie that is passed back and forth if you do not want to keep the password/username stored in the client.