-
Notifications
You must be signed in to change notification settings - Fork 0
Authentication and authorization
Built into ServiceStack is an optional Authentication feature you can use to add Authentication to your services by providing web services to Authenticate existing users, Register new users as well Assign/UnAssign Roles to existing users (if you need them). It's highly pluggable and customizable where you can plug-in your own Auth logic, change the caching and session providers as well as what RDBMS is used to persist UserAuth data.
The high-level overview below shows how all the different parts fit together, which parts are customizable and at what level.
From the overview we can see the built-in AuthProviders that are included:
- Credentials - For authenticating with username/password credentials by posting to the
/auth/credentials
service - Basic Auth - Allowing users to authenticate with Basic Authentication
- Digest Auth - Allowing users to authenticate with HTTP Digest Authentication
- Twitter OAuth (open standard for authorization) - Allow users to Register and Authenticate with Twitter
- Facebook OAuth - Allow users to Register and Authenticate with Facebook
- Custom Credentials - By inheriting CredentialAuthProvider and providing your own Username/Password
TryAuthenticate
implementation
By default the CredentialsAuthProvider
and BasicAuthProvider
validate against users stored in the UserAuth repository. The registration service at /register
allow users to register new users with your service and stores them in your preferred IUserAuthRepository
provider (below). The SocialBootstrapApi uses this to allow new users (without Twitter/Facebook accounts) to register with the website.
A good starting place to create your own Auth provider that relies on username/password validation is to subclass CredentialsAuthProvider
and override the bool TryAuthenticate(service, username, password)
hook so you can add in your own implementation. If you want to make this available via BasicAuth as well you will also need to subclass BasicAuthProvider
with your own custom implementation.
UserAuth Persistence - the IUserAuthRepository
The Authentication module allows you to use your own persistence back-ends but for the most part you should be able to use one of the existing InMemory, Redis, OrmLite, MongoDB or NHibernate adapters. Use the OrmLite or NHibernate adapter if you want to store the Users Authentication information in any of the RDBMS's that OrmLite supports, which as of this writing includes Sql Server, Sqlite, MySql, PostgreSQL and Firebird.
- OrmLite:
OrmLiteAuthRepository
in ServiceStack - Redis:
RedisAuthRepository
in ServiceStack - In Memory:
InMemoryAuthRepository
in ServiceStack - Mongo DB:
MongoDBAuthRepository
in ServiceStack.Authentication.MongoDB - NHibernate:
NHibernateUserAuthRepository
in ServiceStack.Authentication.NHibernate
Caching / Sessions - the ICacheClient
Once authenticated the AuthUserSession model is populated and stored in the Cache using one of ServiceStack's supported Caching providers. ServiceStack's Sessions simply uses the ICacheClient
API so any new provider added can be used for both Session and Caching options. Which currently include the following implementations:
- In Memory:
MemoryCacheClient
in ServiceStack - Redis:
RedisClient
,PooledRedisClientManager
orBasicRedisClientManager
in ServiceStack.Redis - Memcached:
MemcachedClientCache
in ServiceStack.Caching.Memcached - Azure:
AzureCacheClient
in ServiceStack.Caching.Azure
The Auth Feature also allows you to specify your own custom IUserAuthSession
type so you can attach additional metadata to your users session which will also get persisted and hydrated from the cache.
ServiceStack's Authentication, Caching and Session providers are completely new, clean, dependency-free testable APIs that doesn't rely on and is devoid of ASP.NET's existing membership, caching or session provider models.
ServiceStack supports basic authentication and OAuth authentication out of the box. You can read more about Basic and OAuth authentication at Wikipedia:
The Social Bootstrap API example, specifically the AppHost class, shows ways to configure various authentication options. Another good source for ways to configure Authentication is the AuthTests unit test
The minimum configuration needed to get Basic Authentication up and running is the following in the AppHost.Config() (taken from the AuthTests unit test ) :
public override void Configure(Container container)
{
Plugins.Add(new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] {
new BasicAuthProvider()
}));
container.Register<ICacheClient>(new MemoryCacheClient());
var userRep = new InMemoryAuthRepository();
container.Register<IUserAuthRepository>(userRep);
//Add a user for testing purposes
string hash;
string salt;
new SaltedHash().GetHashAndSaltString(Password, out hash, out salt);
userRep.CreateUserAuth(new UserAuth {
Id = 1,
DisplayName = "DisplayName",
Email = "as@if.com",
UserName = UserName,
FirstName = "FirstName",
LastName = "LastName",
PasswordHash = hash,
Salt = salt,
}, Password);
}
This gives you Basic Authentication for all DTOs and Services which require authentication (see below for making DTOs and services require authentication).
However this code specifies that both the CacheClient and UserAuthRepository used are in-memory. Once you've got this working you'll probably want to use a different implementation of IUserAuthRepository
. ServiceStack provides both Redis and OrmLite implementations out the box. You are also free to create your own implementation (just remember to register it in the container).
You may also want to provide a different implementation of ICacheClient
. Cache clients are discussed more below.
The classes in ServiceStack have been designed to provide default behaviour out the box (so-called convention over configuration). They are also highly customisable. Both the default BasicAuthProvider and CredentialsAuthProvider (which it extends) can be extended, and their behaviour over-ridden. An example is below:
using ServiceStack.ServiceInterface;
using ServiceStack.ServiceInterface.Auth;
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
//Add here your custom auth logic (database calls etc)
//Return true if credentials are valid, otherwise false
}
public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
//Fill the IAuthSession with data which you want to retrieve in the app eg:
session.FirstName = "some_firstname_from_db";
//...
//Important: You need to save the session!
authService.SaveSession(session, SessionExpiry);
}
}
Then you need to register your custom credentials auth provider:
//Register all Authentication methods you want to enable for this web app.
Plugins.Add(new AuthFeature(() => new AuthUserSession(),
new IAuthProvider[] {
new CustomCredentialsAuthProvider(), //HTML Form post of UserName/Password credentials
}
));
By default the AuthFeature plugin automatically registers the following (overrideable) Service Routes:
new AuthFeature = {
ServiceRoutes = new Dictionary<Type, string[]> {
{ typeof(AuthService), new[]{"/auth", "/auth/{provider}"} },
{ typeof(AssignRolesService), new[]{"/assignroles"} },
{ typeof(UnAssignRolesService), new[]{"/unassignroles"} },
}
};
e.g. The AuthService
is registered at paths /auth
and /auth/{provider}
where the Provider maps to the IAuthProvider.Provider
property of the registered AuthProviders. The urls for clients authenticating against the built-in AuthProviders are:
- /auth/credentials - CredentialsAuthProvider
- /auth/basic - BasicAuthProvider
- /auth/twitter - TwitterAuthProvider
- /auth/facebook - FacebookAuthProvider
e.g. to Authenticate with your CustomCredentialsAuthProvider (which inherits from CredentialsAuthProvider) you would POST:
POST
localhost:60339/auth/credentials?format=json
{
"UserName": "admin",
"Password": "test"
"RememberMe": true
}
When the client now tries to authenticate with the request above and the auth succeeded, the client will retrieve some cookies with a session id which identify the client on each webservice call.
But how does ServiceStack remember which session id belongs to which client?
For this purpose, ServiceStack uses an ICacheClient.
A cache client is actually a simple key/value-store. When the cache client is used to save client session, the key is the session id and the value is an instance of the interface IAuthSession.
The IAuthSession can be accessed inside a ServiceStack service:
public class SecuredService : RestServiceBase<Secured>
{
public override object OnGet(Secured request)
{
IAuthSession session = this.GetSession();
return new SecuredResponse() { Test = "You're" + session.FirstName };
}
}
ServiceStack uses the CacheClient which was registered in the IoC container:
//Register a external dependency-free
container.Register<ICacheClient>(new MemoryCacheClient() { FlushOnDispose = false });
//Configure an alt. distributed peristed cache that survives AppDomain restarts. e.g Redis
//container.Register<IRedisClientsManager>(c => new PooledRedisClientManager("localhost:6379"));
Tip: If you've got multiple server which run the same ServiceStack service, you can use Redis to share the sessions between these servers.
Please look at SocialBootstrapApi to get a full example.
Of course you can also implement your own - custom - authentication mechanism. You aren't forced to use the built-in ServiceStack auth mechanism.
But how does ServiceStack know, which service needs authentication? This happens with the AuthenticateAttribute.
You simply have to mark your request dto with this attribute:
//Authentication for all HTTP methods (GET, POST...) required
[Authenticate()]
public class Secured
{
public bool Test { get; set; }
}
Now this service can only be accessed if the client is authenticated:
public class SecuredService : RestServiceBase<Secured>
{
public override object OnGet(Secured request)
{
IOAuthSession session = this.GetSession();
return new SecuredResponse() { Test = "You're" + session.FirstName };
}
public override object OnPut(Secured request)
{
return new SecuredResponse() { Test = "Valid!" };
}
public override object OnPost(Secured request)
{
return new SecuredResponse() { Test = "Valid!" };
}
public override object OnDelete(Secured request)
{
return new SecuredResponse() { Test = "Valid!" };
}
}
If you want, that authentication is only required for GET and PUT requests for example, you have to provide some extra parameters to the Authenticate
attribute.
[Authenticate(ApplyTo.Get | ApplyTo.Put)]
Of course Authenticate
can also be placed on top of a service instead on top of a DTO, because it's a normal filter attribute.
ServiceStack also includes a built-in permission based authorization mechanism. More details about how Roles and Permissions work is in this StackOverflow Answer.
Your request DTO can require specific permissions:
[Authenticate()]
//All HTTP (GET, POST...) methods need "CanAccess"
[RequiredRole("Admin")]
[RequiredPermission("CanAccess")]
[RequiredPermission(ApplyTo.Put | ApplyTo.Post, "CanAdd")]
[RequiredPermission(ApplyTo.Delete, "AdminRights", "CanDelete")]
public class Secured
{
public bool Test { get; set; }
}
Now the client needs the permissions...
- "CanAccess" to make a GET request
- "CanAccess", "CanAdd" to make a PUT/POST request
- "CanAccess", "AdminRights" and "CanDelete" to make a DELETE request
Normally ServiceStack calls the method bool HasPermission(string permission)
in IAuthSession. This method checks if the list List<string> Permissions
in IAuthSession contains the required permission.
IAuthSession is stored in a cache client as explained above
You can fill this list in the method OnAuthenticated
you've overriden in the first part of this tutorial.
As Authenticate
, you can mark services (instead of DTO) with RequiredPermission
, too.
- Why ServiceStack?
- What is a message based web service?
- Advantages of message based web services
- Why remote services should use separate DTOs
- Getting Started
- Reference
- Clients
- Formats
- View Engines 4. Razor & Markdown Razor
- Hosts
- Advanced
- Configuration options
- Access HTTP specific features in services
- Logging
- Serialization/deserialization
- Request/response filters
- Filter attributes
- Concurrency Model
- Built-in caching options
- Built-in profiling
- Messaging and Redis
- Form Hijacking Prevention
- Auto-Mapping
- HTTP Utils
- Virtual File System
- Config API
- Physical Project Structure
- Modularizing Services
- Plugins
- Tests
- Other Languages
- Use Cases
- Performance
- How To
- Future