2014-02-03 2 views
2

У меня есть приложение ServiceStack, которое сосуществует с mvc5 в одном веб-проекте. Единственная цель части mvc5 - разместить одно действие контроллера, которое получает обратный вызов из janrain для инициированного javascript социального входа. Я мог бы получить этот обратный вызов в запросе службы SS тоже, но тогда я не знаю, как я буду перенаправлять на returnUrl, который проходит через весь путь из контекста javascript. Даже если бы я смог это понять, мой вопрос все равно был бы таким же.Ручная принудительная аутентификация пользователя без выдачи запроса на аутентификацию

Внутри действия контроллера, как только я проверяю, что предоставленный токен janrain разрешает пользователю в моей системе, мне нужно вручную сообщить ServiceStack «Эй, доверься мне, этому человеку разрешено».

Все мои поиски приводят к некоторому коду по линиям следующего фрагмента кода:

var authService = AppHostBase.Resolve<AuthService>(); 
       authService.RequestContext = System.Web.HttpContext.Current.ToRequestContext(); 
       var AuthResponse = authService.Authenticate(new Auth 
       { 
        provider = "credentials", 
        UserName = user.user_id, 
        Password = user.password, 
        RememberMe = true 
       }); 

Моя первая проблема в том, что я храню хеширования паролей (я поддерживаю социальную логин, а также руководство Логин), так что я не знаю пароль пользователя (и не должен).

Моя вторая проблема заключается в том, что этот код работает только для SS 3.X, а не 4.X. Мне требуется ServiceStack.ServiceInterface.dll, который таинственно отсутствует в 4.X.

Есть ли короткий и точный способ ручной аутентификации пользователя с SS на стороне сервера?

Благодаря

EDIT: До сих пор это то, что я делаю: (Это не окончательный код - я заметил некоторые вещи, которые я не знаю, что делать с):

public class UsernameOnlyAuthorizationService : Service 
    { 
     public object Post(UsernameOnlyLoginRequest request) 
     { 
      var authProvider = new UsernameOnlyAuthProvider(); 
      authProvider.Authenticate(this, GetSession(), new Authenticate() 
      { 
       UserName = request.username, 
       Password = "NotRelevant", 
       RememberMe = true 
      }); 

      return HttpResult.Redirect(request.returnUrl); 
     } 
    } 


public class UsernameOnlyAuthProvider : CredentialsAuthProvider 
    { 
     public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
     { 
      var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver()); 
      ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>(); 
      var session = authService.GetSession(); 
      IUserAuth userAuth; 
      var user = db.Users.FirstOrDefault(u => u.Username == userName); 

      if (user != null) 
      { 
       //AssertNotLocked(userAuth); 

       //session.PopulateWith(userAuth); 
       session.Id = user.Id.ToString(); 
       session.UserName = user.Username; 
       session.FirstName = user.FirstName; 
       session.LastName = user.LastName; 
       session.IsAuthenticated = true; 
       session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture); 
       session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId) 
        .ConvertAll(x => (IAuthTokens)x); 

       return true; 
      } 

      return false; 
     } 
    } 

И из моей JanRain коды успеха обратного вызова Я называю это так:

HostContext.ResolveService<UsernameOnlyAuthorizationService>().Post(new UsernameOnlyLoginRequest() {username = user.Username, returnUrl= returnUrl}); 

Это, кажется, работает хорошо, однако, я не могу заставить его вспомнить свой сеанс через браузер закрытие s. Я hardcoding RememberMe = true - почему это не работает?

ответ

2

Я бы сделал это, создав внутреннюю службу, которую вы можете вызывать из своего действия с контроллером MVC5, где вам требуется только передать имя пользователя для аутентифицированного пользователя.

public class JanrainSuccessService : Service 
{ 
    public void CreateSessionFor(string username) 
    { 
     var repository = TryResolve<IAuthRepository>().AsUserAuthRepository(GetResolver()); 
     var user = repository.GetUserAuthByUserName(username); 
     var session = GetSession(); 
     session.PopulateWith(user); 
     session.IsAuthenticated = true; 
     session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture); 
     session.ProviderOAuthAccess = repository.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x); 
    } 
} 

Код в этом методе, фактически то же самое, что может используется CredentialsAuthProvider, но имеет то преимущество, что не требует пароля пользователя. (см TryAuthenticatemethod here для оригинального кода)

В вашем MVC5 метод действия контроллера вам нужно будет позвонить:

HostContext.ResolveService<JanrainSuccessService>().CreateSessionFor(user.user_id); 

Это предполагает, что у вас есть действительный хранилище пользователей настроен для сопоставления с именем пользователя в ,


Вы должны обновить свой код, чтобы быть:

public class UsernameOnlyAuthorizationService : Service 
{ 
    public object Post(UsernameOnlyLoginRequest request) 
    { 
     var authProvider = new UsernameOnlyAuthProvider(); 
     authProvider.Authenticate(this, GetSession(), new Authenticate() 
     { 
      UserName = request.username, 
      Password = "NotRelevant", 
      RememberMe = true 
     }); 

     // Remember the session 
     base.Request.AddSessionOptions(SessionOptions.Permanent); 

     return HttpResult.Redirect(request.returnUrl); 
    } 
} 

public class UsernameOnlyAuthProvider : CredentialsAuthProvider 
{ 
    public override bool TryAuthenticate(IServiceBase authService, string userName, string password) 
    { 
     var authRepo = authService.TryResolve<IAuthRepository>().AsUserAuthRepository(authService.GetResolver()); 
     ReferScienceDataContext db = authService.TryResolve<ReferScienceDataContext>(); 
     var session = authService.GetSession(); 
     var user = db.Users.FirstOrDefault(u => u.Username == userName); 

     if (user == null) 
      return false; 

     session.Id = user.Id.ToString(); 
     session.UserName = user.Username; 
     session.FirstName = user.FirstName; 
     session.LastName = user.LastName; 
     session.IsAuthenticated = true; 
     session.UserAuthId = user.Id.ToString(CultureInfo.InvariantCulture); 
     session.ProviderOAuthAccess = authRepo.GetUserAuthDetails(session.UserAuthId).ConvertAll(x => (IAuthTokens)x); 
     return true; 
    } 
} 
+1

Это выглядит как отличное решение.Я собираюсь дать ему попытку и, надеюсь, я смогу принять ваш пост как ответ в ближайшее время. Спасибо. – t316

+0

Я заметил, что вы написали этот маленький класс аутентификатора в качестве службы SS. Технически, это мог быть любой простой старый класс, который может быть введен в зависимость, правильно? Сначала я думал, что это проблема безопасности, потому что я думал о SS как о дистанционно вызываемых услугах. Тем не менее, кажется, что эти унаследованные классы служб могут быть вызваны как локальная служба, так и удаленная служба. Правильно ли я полагаю, что JanrainSuccessService нельзя назвать удаленно, потому что маршрут не определен? Очевидно, я не хочу, чтобы какое-либо удаленное приложение javascript могло выдавать себя за кого-то ... – t316

+0

@ t316 Я добавил его как услугу, потому что он автоматически подключает решение сеанса, и для решения других зависимостей меньше кода. Но вы правы, что вы не делаете этого *, если вы сами разрешаете зависимости из HostContext. Что касается безопасности, доступ к этому методу отсутствует, потому что нет пути к нему. И имя метода не является именем метода 'HTTP', таким как' Get' или 'Post'. Вы можете подтвердить это, просмотрев метаданные, где метод не будет показан. – Scott

Смежные вопросы