8

Zasadniczo chcę pokazać przyjazny komunikat, gdy ktoś nie jest częścią roli wymienionej w moim atrybucie. Obecnie moja aplikacja spluwa użytkownika z powrotem do ekranu logowania. Czytałem kilka postów, które mówią o tworzeniu niestandardowego atrybutu, który rozszerza [AuthorizeAttribute], ale myślę, że musi to być coś z pudełka, aby to zrobić?atrybut metody działania kontrolera .net MVC

Czy ktoś może wskazać mi właściwy kierunek, w którym muszę wyglądać, aby nie wysłać go do formularza logowania, ale po prostu zastrzelić wiadomość "nie autoryzowana"?

Odpowiedz

2

Jeśli prostota lub całkowita kontrola logiki jest to, co chcesz, możesz nazwać to w swoim sposobie działania:

User.IsInRole("NameOfRole"); 

Zwraca bool i można zrobić resztę logiki w zależności od tego wyniku.

Kolejny że Użyłem w niektórych przypadkach jest:

System.Web.Security.Roles.GetRolesForUser(); 

myślę, że zwraca ciąg [], ale nie zacytować mnie na to.

EDIT: Przykładem zawsze pomaga ...

public ActionResult AddUser() 
{ 
    if(User.IsInRoles("SuperUser") 
    { 
     return View("AddUser"); 
    } 
    else 
    { 
     return View("SorryWrongRole"); 
    } 
} 

Dopóki twój typ zwracany jest "ActionResult" można powrócić dowolnym z dopuszczalnych typów zwrotu (ViewResult, PartialViewResult, RedirectResult, JsonResult ...)

+0

więc używając tej logiki, musiałbym zwrócić częściowe widoki z "przyjaznymi wiadomościami" poprawnymi? Czy nie można objąć całej metody działania atrybutem, który robi to samo? – Kyle

+0

Dodałem przykład powyżej. Inną opcją jest oczywiście pisanie własnego atrybutu, o którym wspomniałeś (który byłby najczystszy, choć trudniejszy do testowania jednostkowego), ale nie jest to z pewnością podejście nieszablonowe. –

0

Nieoczekiwane zachowanie polega na tym, że atrybut [Autoryzuj] zwraca HTTP 401. Moduł FormsAuthenticationModule (który jest ładowany domyślnie) przechwytuje to 401 i przekierowuje użytkownika na stronę logowania. Spójrz na System.Web.Security.FormsAuthenticationModule :: OnLeave w Reflectorze, aby zobaczyć co mam na myśli.

Jeśli chcesz AuthorizeAttribute coś zrobić inne niż powrotnej HTTP 401, będziesz musiał zastąpić metodę AuthorizeAttribute :: HandleUnauthorizedRequest i wykonywać swoją niestandardową logikę tam. Alternatywnie, wystarczy zmienić tę część ~ \ Web.config:

<forms loginUrl="~/Account/LogOn" timeout="2880" /> 

I zrobić to wskazywać na inny adres URL, jak ~/AccessDenied.

3

Wpadłem na ten problem kilka dni temu, a rozwiązanie jest nieco szczegółowe, ale tutaj są ważne fragmenty. W trybie AuthorizeAttribute metoda HttpUnauthorizedResult zwraca wartość HttpUnauthorizedResult, gdy autoryzacja kończy się niepowodzeniem, co sprawia, że ​​zwracanie wyniku niestandardowego jest nieco utrudnione.

W efekcie stworzyłem klasę CustomAuthorizeAttribute i nadpisałem metodę OnAuthorization, aby zamiast tego wygenerować wyjątek. Mogę następnie przechwycić ten wyjątek za pomocą niestandardowej procedury obsługi błędów i wyświetlić niestandardową stronę błędu zamiast zwracać 401 (nieautoryzowane).

public class CustomAuthorizeAttribute : AuthorizeAttribute 
{ 
    public virtual void OnAuthorization(AuthorizationContext filterContext) { 
     if (filterContext == null) { 
      throw new ArgumentNullException("filterContext"); 
     } 

     if (AuthorizeCore(filterContext.HttpContext)) { 
      HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
      cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
      cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
     } 
     else { 
      // auth failed, redirect to login page 
      // filterContext.Result = new HttpUnauthorizedResult(); 

      throw new HttpException ((int)HttpStatusCode.Unauthorized, "Unauthorized");     
     } 
    } 
} 

następnie w Twojej web.config można ustawić niestandardowe procedury obsługi dla konkretnych błędów:

<customErrors mode="On" defaultRedirect="~/Error"> 
     <error statusCode="401" redirect="~/Error/Unauthorized" /> 
     <error statusCode="404" redirect="~/Error/NotFound" /> 
    </customErrors> 

a następnie zaimplementować własną ErrorController służyć do stron niestandardowych.

W IIS7 należy sprawdzić ustawienie Response.TrySkipIisCustomErrors = true;, aby włączyć niestandardowe błędy.

6

Mogę trochę spóźnić się dodając 0,02 USD, ale kiedy tworzysz CustomAuthorizationAttribue, możesz użyć AuthorizationContext.Result property, aby określić, gdzie metoda AuthorizeAttribute.HandleUnauthorizedRequest kieruje użytkownika.

Tutaj jest bardzo prosty przykład, który pozwala określić adres URL, gdzie użytkownik powinna być wysłana po nieudanej autoryzacji:

public class Authorize2Attribute : AuthorizeAttribute 
{ 
    // Properties 

    public String RedirectResultUrl { get; set; } 

    // Constructors 

    public Authorize2Attribute() 
     : base() 
    { 
    } 

    // Overrides 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     if (String.IsNullOrEmpty(RedirectResultUrl)) 
      base.HandleUnauthorizedRequest(filterContext); 

     else 
      filterContext.Result = new RedirectResult(RedirectResultUrl); 
    } 
} 

A gdybym chciał przekierować użytkownika do/błąd/Nieautoryzowane jak sugeruje w poprzednim poście:

[Authorize2(Roles = "AuthorizedUsers", RedirectResultUrl = "/Error/Unauthorized")] 
public ActionResult RestrictedAction() 
{ 
    // TODO: ... 
} 
+0

Zrobiłem podobną rzecz, ale sprawdzam, czy użytkownik jest uwierzytelniony. To pozwala mi odrzucać użytkowników, ponieważ nie są oni w roli, ale nie są proszeni o zalogowanie się –

2

Bardzo podobny do crazyarabian, ale tylko przekierować do mojego ciąg jeśli użytkownik jest rzeczywiście uwierzytelnione. Pozwala to na przekierowanie atrybutu na standardową stronę logowania, jeśli nie są aktualnie zalogowani, ale na inną stronę, jeśli nie mają oni uprawnień dostępu do adresu URL.

public class EnhancedAuthorizeAttribute : AuthorizeAttribute 
{ 
    public string UnauthorizedUrl { get; set; } 

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
    { 
     var redirectUrl = UnauthorizedUrl; 
     if (filterContext.HttpContext.User.Identity.IsAuthenticated && !string.IsNullOrWhiteSpace(redirectUrl)) 
     { 
      filterContext.Result = new RedirectResult(redirectUrl); 
     } 
     else 
     { 
      base.HandleUnauthorizedRequest(filterContext); 
     } 
    } 
} 
Powiązane problemy