Пользовательская аутентификация ServiceStack для интрасетей Windows
Целый день ломал голову над этим и пришел к следующему.
Сначала вариант использования:
Вы находитесь в корпоративной интрасети, используя проверку подлинности Windows. Вы устанавливаете режим аутентификации = "Windows" в своем web.config, и все!
Ваша стратегия такова:
Вы не знаете, кто этот пользователь, потому что он не входит в вашу таблицу пользователей, группу ActiveDirectory или что-то еще. В этом случае вы даете им роль «гостя» и соответствующим образом обрезаете пользовательский интерфейс. Может быть, дайте им ссылку на электронную почту, чтобы запросить доступ.
У вас есть пользователь в списке пользователей, но ему не назначена роль. Поэтому дайте им роль «пользователя» и обрежьте пользовательский интерфейс, как указано выше. Может быть, они и видят свои вещи, но больше ничего.
Пользователь находится в вашем списке и ему назначена роль. Первоначально вы назначите роль, вручную обновив таблицу UserAuth в базе данных. В конце концов у вас будет служба, которая будет делать это для авторизованных пользователей.
Итак, приступим к коду.
Сторона сервера
На уровне службы ServiceStack мы создаем поставщика авторизации настраиваемых учетных данных в соответствии с https://github.com/ServiceStack/ServiceStack/wiki/Authentication-and-authorization
public class CustomCredentialsAuthProvider : CredentialsAuthProvider
{
public override bool TryAuthenticate(IServiceBase authService, string userName, string password)
{
//NOTE: We always authenticate because we are always a Windows user!
// Yeah, it's an intranet
return true;
}
public override void OnAuthenticated(IServiceBase authService, IAuthSession session, IOAuthTokens tokens, Dictionary<string, string> authInfo)
{
// Here is why we set windows authentication in web.config
var userName = HttpContext.Current.User.Identity.Name;
// Strip off the domain
userName = userName.Split('\\')[1].ToLower();
// Now we call our custom method to figure out what to do with this user
var userAuth = SetUserAuth(userName);
// Patch up our session with what we decided
session.UserName = userName;
session.Roles = userAuth.Roles;
// And save the session so that it will be cached by ServiceStack
authService.SaveSession(session, SessionExpiry);
}
}
И вот наш пользовательский метод:
private UserAuth SetUserAuth(string userName)
{
// NOTE: We need a link to the database table containing our user details
string connStr = ConfigurationManager.ConnectionStrings["YOURCONNSTRNAME"].ConnectionString;
var connectionFactory = new OrmLiteConnectionFactory(connStr, SqlServerDialect.Provider);
// Create an Auth Repository
var userRep = new OrmLiteAuthRepository(connectionFactory);
// Password not required.
const string password = "NotRequired";
// Do we already have the user? IE In our Auth Repository
UserAuth userAuth = userRep.GetUserAuthByUserName(userName);
if (userAuth == null ){ //then we don't have them}
// If we don't then give them the role of guest
userAuth.Roles.Clear();
userAuth.Roles.Add("guest")
// NOTE: we are only allowing a single role here
// If we do then give them the role of user
// If they are one of our team then our administrator have already given them a role via the setRoles removeRoles api in ServiceStack
...
// Now we re-authenticate out user
// NB We need userAuthEx to avoid clobbering our userAuth with the out param
// Don't you just hate out params?
// And we re-authenticate our reconstructed user
UserAuth userAuthEx;
var isAuth = userRep.TryAuthenticate(userName, password, out userAuthEx);
return userAuth;
}
В appHost Configure добавьте следующие ResponseFilters в конце функции.
ResponseFilters.Add((request, response, arg3) => response.AddHeader("X-Role",request.GetSession(false).Roles[0]));
ResponseFilters.Add((request, response, arg3) => response.AddHeader("X-AccountName", request.GetSession(false).UserName));
Это отправляет некоторые дополнительные заголовки клиенту, чтобы мы могли обрезать пользовательский интерфейс в соответствии с ролью пользователя.
Сторона клиента
На стороне клиента, когда мы отправляем первый запрос на сервер, мы отправляем имя пользователя и пароль, как того требует пользовательская аутентификация. Для обоих установлено значение «NotRequired», поскольку мы будем знать, кто пользователь на стороне сервера, через HttpContext.Current.User.Identity.Name.
Следующее использует AngularJS для связи AJAX.
app.run(function($templateCache, $http, $rootScope) {
// Authenticate and get X-Role and X-AccountName from the response headers and put it in $rootScope.role
// RemeberMe=true means that the session will be cached
var data={"UserName" : "NotRequired", "Password" : "NotRequired", "RememberMe": true };
$http({ method : 'POST', url : '/json/reply/Auth', data : data }).
success(function (data, status, headers, config) {
// We stash this in $rootScope for later use!
$rootScope.role = headers('X-Role');
$rootScope.accountName = headers('X-AccountName');
console.log($rootScope.role);
console.log($rootScope.role);
}).
error(function (data, status, headers, config) {
// NB we should never get here because we always authenticate
toastr.error('Not Authenticated\n' + status, 'Error');
});
};
person
pjsvis
schedule
27.03.2013