ElenaRez Ответов: 2

Невозможно изменить форму после правильной авторизации пользователя в форме входа в систему


Hi. I'm using DirectoryServices.AccountManagement for authorizing users to log into my web application. The code I used is like the following for authorizing and it can correctly authorize active directory users. As I read a variety of articles, I need to write something like [Authorize(Users="DOMAIN\UserName")] on top my controller classes in order to specify that which controller, the user has access. But now my problem is what should I write in the body of "if (ctx.ValidateCredentials(userName, password)" after the user' authorization is successful. I wrote something like "return this.RedirectToLocal(returnUrl);" but after clicking the login button, although in the console it prints "You are logged in" but still the login form remains. I appreciate if anyone can suggest me a solution accordingly.

 [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Signin(SigninViewModel model, string returnUrl = null)
        {
            this.ViewData["ReturnUrl"] = returnUrl;

            using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "tehran.iri"))
            {
                // validate the user's credentials
                //var result = ctx.ValidateCredentials(model.UserName, model.Password);
                //    try { 
                if (ctx.ValidateCredentials(model.UserName, model.Password))
                {
                    // credentials are OK --> allow user in
                    Debug.Writeline("You are logged in");
                    return this.RedirectToLocal(returnUrl);

                }
                else
                {
                    this.TempData["ErrorMessage"] = "The username and/or password are incorrect!";

                    return this.View(model);
                    // credentials aren't OK --> send back error message
                }
       }
}


Что я уже пробовал:

HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Signin(SigninViewModel model, string returnUrl = null)
        {
            this.ViewData["ReturnUrl"] = returnUrl;

            using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "tehran.iri"))
            {
                // validate the user's credentials
                //var result = ctx.ValidateCredentials(model.UserName, model.Password);
                //    try { 
                if (ctx.ValidateCredentials(model.UserName, model.Password))
                {
                    // credentials are OK --> allow user in
                    Debug.Writeline("You are logged in");
                    return this.RedirectToLocal(returnUrl);

                }
                else
                {
                    this.TempData["ErrorMessage"] = "The username and/or password are incorrect!";

                    return this.View(model);
                    // credentials aren't OK --> send back error message
                }
       }
}

2 Ответов

Рейтинг:
1

MadMyche

Это займет еще немного отладки... Я бы предложил добавить в эту строку, чтобы проверить значение returnUrl который имеет значение по умолчанию нулевой в объявлении метода; и это довольно трудно перенаправить туда

if (ctx.ValidateCredentials(model.UserName, model.Password))
{
	// credentials are OK --> allow user in
	Debug.Writeline("You are logged in");
	Debug.Writeline(string.Format("Redirection to {0}", returnUrl);  // add this
	return this.RedirectToLocal(returnUrl);
}


ElenaRez

Спасибо за ваш ответ. Я вставил то, что вы предложили, и после запуска проекта мне было показано "перенаправление на /" в консоли отладки. Как я могу это исправить? Даже я изменил свой метод входа, как показано ниже, но не было никаких изменений для результата перенаправления в консоли отладки:

public async Task<iactionresult> Signin(SigninViewModel model, string returnUrl = null)

Рейтинг:
0

Richard Deeming

Проблема в том, что вы не установили ничего, что указывало бы на то, что пользователь вошел в систему.

Вы проверяете учетные данные и перенаправляетесь на сайт returnUrl, но этот перенаправленный запрос будет анонимным. То Authorize фильтр увидит анонимный запрос на ресурс, требующий аутентификации, и перенаправит вас обратно на страницу входа в систему.

Самый простой подход, вероятно, состоял бы в том, чтобы сохранить аутентифицированное имя пользователя в сеансе и использовать его в AuthenticateRequest событие для установки аутентифицированного пользователя для запроса. Например:

Вспомогательный класс:

public static class AuthenticationHelper
{
    private const string SessionKey = "AuthenticationHelper.UserName";
    
    public static void MarkAsAuthenticated(this HttpSessionStateBase session, string authenticatedUserName)
    {
        session[SessionKey] = authenticatedUserName;
    } 
    
    public static IPrincipal GetAuthenticatedUser(this HttpSessionState session)
    {
        string authenticatedUserName = (string)session[SessionKey];
        if (string.IsNullOrEmpty(authenticatedUserName)) return null;
        return new GenericPrincipal(new GenericIdentity(authenticatedUserName), Array.Empty<string>());
    }
}
Войдите в действие:
if (ctx.ValidateCredentials(model.UserName, model.Password))
{
    // credentials are OK --> allow user in
    Debug.Writeline("You are logged in");
    Session.MarkAsAuthenticated(model.UserName);
    return RedirectToLocal(returnUrl);
}
Global.asax.cs:
protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    IPrincipal user = Session.GetAuthenticatedUser();
    if (user != null) Context.User = user;
}
Если вы используете [Authorize(Users = "...")], имена пользователей должны будут соответствовать тому, что пользователь ввел при входе в систему.

NB: Обычно предпочтительнее использовать роли вместо пользователей, так что вам не придется перекомпилировать свой код, чтобы изменить, кто имеет доступ к чему.

Особое примечание 2: Если все, кто входит в систему, могут получить доступ ко всем действиям, и вам не нужно ограничивать конкретные действия конкретными пользователями, вы можете просто использовать [Authorize] вместо.



Редактировать: Ибо ASP.NET ядро, вам нужно будет использовать пользовательское промежуточное программное обеспечение вместо Global.asax файл.
Перенести обработчики и модули HTTP, чтобы ASP.NET ядра промежуточного | Майкрософт документы[^]

Вам также нужно будет обновить помощник, чтобы учесть новый ISession интерфейс.

Вспомогательный класс:
public static class AuthenticationHelper
{
    private const string SessionKey = "AuthenticationHelper.UserName";
    
    public static void MarkAsAuthenticated(this Microsoft.AspNetCore.Http.ISession session, string authenticatedUserName)
    {
        session.SetString(SessionKey, authenticatedUserName);
    } 
    
    public static ClaimsPrincipal GetAuthenticatedUser(this Microsoft.AspNetCore.Http.ISession session)
    {
        string authenticatedUserName = session.GetString(SessionKey);
        if (string.IsNullOrEmpty(authenticatedUserName)) return null;
        return new GenericPrincipal(new GenericIdentity(authenticatedUserName), Array.Empty<string>());
    }
}
Промежуточный слой:
public class CustomAuthenticationMiddleware
{
    private readonly RequestDelegate _next;
    
    public CustomAuthenticationMiddleware(RequestDelegate next)
    {
        _next = next;
    }
    
    public async Task Invoke(HttpContext context)
    {
        ClaimsPrincipal user = context.Session.GetAuthenticatedUser();
        if (user != null) context.User = user;
        await _next(context);
    }
}

public static class CustomAuthenticationMiddlewareExtensions
{
    public static IApplicationBuilder UseCustomAuthentication(this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<CustomAuthenticationMiddleware>();
    }    
}
Запуск:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    ...
    app.UseCustomAuthentication();
    app.UseAuthorization();
    ...
}
Убедитесь, что вы добавляете строки аутентификации / авторизации после UseRouting, но раньше UseEndpoints.

Вам также нужно будет позвонить AddSession в ConfigureServices метод и UseSession в Configure метод, описанный в документации:
Сессия в ASP.NET ядро | Microsoft Docs[^]

То UseSession вызов должен будет появиться до того, как UseCustomAuthentication вызов.


ElenaRez

Большое вам спасибо за Ваш полезный ответ. Я внедряю asp.net cor 3.1 и у меня нет файла Global.asax.cs. Вместо этого у меня есть appsettings.jason и startup.cs. Как я могу использовать ваш файл Global.asax в своем собственном проекте?

Richard Deeming

Ибо ASP.NET ядро, вместо этого вам нужно будет использовать пользовательское промежуточное программное обеспечение:
Перенести обработчики и модули HTTP, чтобы ASP.NET ядра промежуточного | Майкрософт документы[^]

Richard Deeming

GenericPrincipal[^] является ClaimsPrincipal, поэтому вам просто нужно изменить тип возвращаемого значения метода расширения и тип переменной в промежуточном программном обеспечении.

ElenaRez

Я вставил то, что вы сказали, в свой код, и теперь пользователь может войти на мой сайт. На моем сайте у меня есть 4 контроллера, и поверх каждого я добавил [авторизовать], как вы предложили, чтобы позволить всем пользователям работать с ними. Но теперь проблема заключается в том, что когда пользователь нажимает на соответствующий значок меню, все эти страницы отображаются белыми страницами. Я буду признателен, если вы расскажете мне об этой проблеме