Estou tentando criar um atributo de autorização personalizado no ASP.NET Core. Nas versões anteriores, era possível substituir bool AuthorizeCore(HttpContextBase httpContext)
. Mas isso não existe mais no AuthorizeAttribute
.
Qual é a abordagem atual para criar um AuthorizeAttribute personalizado?
O que estou tentando realizar: estou recebendo um ID de sessão na Autorização de Cabeçalho. A partir desse ID, saberei se uma ação específica é válida.
Respostas:
A abordagem recomendada pela equipe do ASP.Net Core é usar o novo design de política, que está totalmente documentado aqui . A idéia básica por trás da nova abordagem é usar o novo atributo [Autorizar] para designar uma "política" (por exemplo,
[Authorize( Policy = "YouNeedToBe18ToDoThis")]
onde a política está registrada no Startup.cs do aplicativo para executar algum bloco de código (por exemplo, garantir que o usuário tenha uma reivindicação de idade) com idade igual ou superior a 18 anos).O design da política é um ótimo complemento para a estrutura e a equipe do ASP.Net Security Core deve ser elogiada por sua introdução. Dito isto, não é adequado para todos os casos. A desvantagem dessa abordagem é que ela falha em fornecer uma solução conveniente para a necessidade mais comum de simplesmente afirmar que um determinado controlador ou ação requer um determinado tipo de declaração. No caso em que um aplicativo pode ter centenas de permissões discretas que controlam operações CRUD em recursos REST individuais ("CanCreateOrder", "CanReadOrder", "CanUpdateOrder", "CanDeleteOrder" etc.), a nova abordagem exige repetições um a um um mapeamento entre um nome de política e um nome de reivindicação (por exemplo,
options.AddPolicy("CanUpdateOrder", policy => policy.RequireClaim(MyClaimTypes.Permission, "CanUpdateOrder));
) ou escrevendo algum código para executar esses registros em tempo de execução (por exemplo, leia todos os tipos de declaração de um banco de dados e execute a chamada acima em um loop). O problema com essa abordagem na maioria dos casos é que ela é desnecessária.Embora a equipe do ASP.Net Core Security recomende nunca criar sua própria solução, em alguns casos, essa pode ser a opção mais prudente para começar.
A seguir, uma implementação que usa o IAuthorizationFilter para fornecer uma maneira simples de expressar um requisito de declaração para um determinado controlador ou ação:
fonte
new ForbidResult()
, não funciona (causa exceção / 500) porque não possui um esquema de autorização associado. O que eu usaria para este caso?Eu sou a pessoa de segurança asp.net.
Em primeiro lugar, peço desculpas por nada disso estar documentado ainda fora da amostra da loja de música ou dos testes de unidade, e tudo ainda está sendo refinado em termos de APIs expostas.A documentação detalhada está aqui .Não queremos que você escreva atributos de autorização personalizados. Se você precisar fazer isso, fizemos algo errado. Em vez disso, você deve escrever requisitos de autorização .
A autorização atua sobre identidades. Identidades são criadas por autenticação.
Você diz nos comentários que deseja verificar um ID de sessão em um cabeçalho. O seu ID de sessão seria a base da identidade. Se você quisesse usar o
Authorize
atributo, escreveria um middleware de autenticação para pegar esse cabeçalho e transformá-lo em um autenticadoClaimsPrincipal
. Você então verificaria isso dentro de um requisito de autorização. Os requisitos de autorização podem ser tão complicados quanto você desejar, por exemplo, aqui está um que aceita uma reivindicação de data de nascimento na identidade atual e autoriza se o usuário tiver mais de 18 anos;Então, na sua
ConfigureServices()
função, você ligariaE, finalmente, aplique-o a um controlador ou método de ação com
fonte
ManageStore
amostra Requisito da Music Store. Como está na amostra, existe apenas uma maneira de "permitir tudo ou nada" para fazê-lo. Temos então que criar uma nova política para todas as permutações possíveis? ou seja, "Usuários / Leitura", "Usuários / Criar", "Usuários / AtribuirRole", "Usuários / Excluir" se quisermos reivindicações refinadas? Parece um trabalho de configuração para fazê-lo funcionar e abundância de políticas apenas para gerenciar reivindicações em vez de um[ClaimsAutzorization("User", "Read", "Create", "Delete", "Assign")]
atributo?[CustomAuthorize(Operator.And, Permission.GetUser, Permission.ModifyUser)]
. Eu poderia usar um único atributo personalizado de várias maneiras, simplesmente modificando os parâmetros do construtor.IAuthorizeData.Policy
) e provedores de políticas personalizadas para superar essa flagrante supervisão, em vez de abordá-la dentro da estrutura. Eu pensei que não deveríamos estar criando nossas próprias implementações? Você não deixou escolha para vários de nós, exceto para reimplementar a autorização do zero (novamente), e desta vez sem o benefício doAuthorize
atributo antigo da API da Web . Agora temos que fazer isso no nível do filtro de ação ou do middleware.Parece que, com o ASP.NET Core 2, você pode herdar novamente
AuthorizeAttribute
, basta implementarIAuthorizationFilter
(ouIAsyncAuthorizationFilter
):fonte
OnAuthorization
implementação precisar aguardar um método assíncrono, você deve implementar, emIAsyncAuthorizationFilter
vez disso,IAuthorizationFilter
seu filtro será executado de forma síncrona e a ação do controlador será executada independentemente do resultado do filtro.Baseado na excelente resposta de Derek Greer , eu fiz isso com enumerações.
Aqui está um exemplo do meu código:
fonte
Você pode criar seu próprio AuthorizationHandler que encontrará atributos personalizados em seus Controladores e Ações e passá-los para o método HandleRequirementAsync.
Em seguida, você pode usá-lo para qualquer atributo personalizado necessário em seus controladores ou ações. Por exemplo, para adicionar requisitos de permissão. Basta criar seu atributo personalizado.
Em seguida, crie um requisito para adicionar à sua política
Em seguida, crie o AuthorizationHandler para seu atributo personalizado, herdando o AttributeAuthorizationHandler que criamos anteriormente. Será passado um IEnumerable para todos os seus atributos personalizados no método HandleRequirementsAsync, acumulado do seu Controller e Action.
E finalmente, no seu método Startup.cs ConfigureServices, adicione seu AuthorizationHandler personalizado aos serviços e adicione sua Política.
Agora você pode simplesmente decorar seus Controladores e Ações com seu atributo personalizado.
fonte
Fácil: não crie o seu próprio
AuthorizeAttribute
.Para cenários de autorização pura (como restringir o acesso apenas a usuários específicos), a abordagem recomendada é usar o novo bloco de autorização: https://github.com/aspnet/MusicStore/blob/1c0aeb08bb1ebd846726232226279bbe001782e1/samples/MusicStore/Startup.cs#L84 -L92
Para autenticação, é melhor lidar com o nível do middleware.
O que você está tentando alcançar exatamente?
fonte
Se alguém apenas deseja validar um token de portador na fase de autorização usando as práticas de segurança atuais, você pode,
adicione isso ao seu Startup / ConfigureServices
e isso na sua base de código,
Se o código não atingir
context.Succeed(...)
, falhará de qualquer maneira (401).E então em seus controladores você pode usar
fonte
A maneira moderna é AuthenticationHandlers
em startup.cs add
IUserService é um serviço que você faz onde possui nome de usuário e senha. basicamente, ele retorna uma classe de usuário que você usa para mapear suas reivindicações.
Em seguida, você pode consultar essas declarações e todos os dados que você mapeou, existem alguns, dê uma olhada na classe ClaimTypes
você pode usar isso em um método de extensão e obter qualquer um dos mapeamentos
Essa nova maneira, eu acho que é melhor do que
fonte
Até o momento em que escrevo, acredito que isso possa ser conseguido com a interface IClaimsTransformation no asp.net core 2 e acima. Acabei de implementar uma prova de conceito que é compartilhável o suficiente para postar aqui.
Para usar isso no seu Controller, basta adicionar um apropriado
[Authorize(Roles="whatever")]
aos seus métodos.No nosso caso, toda solicitação inclui um cabeçalho de autorização que é um JWT. Este é o protótipo e acredito que faremos algo super próximo disso em nosso sistema de produção na próxima semana.
Futuros eleitores, considere a data da redação ao votar. A partir de hoje,
works on my machine.
você provavelmente desejará mais tratamento e registro de erros em sua implementação.fonte
Para autorização em nosso aplicativo. Tivemos que chamar um serviço com base nos parâmetros passados no atributo de autorização.
Por exemplo, se quisermos verificar se o médico que está logado pode ver as consultas do paciente, passaremos "View_Appointment" para customizar o atributo de autorização e verificaremos se o serviço de DB está correto e com base nos resultados que iremos autorizar. Aqui está o código para este cenário:
E na ação da API, usamos assim:
fonte
A resposta aceita ( https://stackoverflow.com/a/41348219/4974715 ) não é realisticamente mantida ou adequada porque "CanReadResource" está sendo usado como uma reivindicação (mas deve ser essencialmente uma política na realidade, IMO). A abordagem na resposta não é boa na maneira como foi usada, porque se um método de ação exigir muitas configurações de declarações diferentes, com essa resposta, você deverá escrever repetidamente algo como ...
Então, imagine quanta codificação seria necessária. Idealmente, "CanReadResource" deve ser uma política que use muitas declarações para determinar se um usuário pode ler um recurso.
O que faço é criar minhas políticas como uma enumeração e, em seguida, percorrer e configurar os requisitos dessa forma ...
A classe DefaultAuthorizationRequirement se parece com ...
Observe que o código acima também pode ativar o pré-mapeamento de um usuário para uma política em seu armazenamento de dados. Portanto, ao compor declarações para o usuário, você basicamente recupera as políticas que foram pré-mapeadas para o usuário direta ou indiretamente (por exemplo, porque o usuário tem um determinado valor de declaração e esse valor de identificação foi identificado e mapeado para uma política, como que ele fornece mapeamento automático para usuários que também possuem esse valor de declaração) e inscreve as políticas como declarações, de modo que, no manipulador de autorização, você pode simplesmente verificar se as declarações do usuário contêm requisito. reivindicações. Isso é para uma maneira estática de atender a um requisito de política, por exemplo, o requisito "Primeiro nome" é de natureza bastante estática. Assim,
Um requisito dinâmico pode ser a verificação da faixa etária etc., e as políticas que usam esses requisitos não podem ser pré-mapeadas para os usuários.
Um exemplo de verificação dinâmica de declarações de política (por exemplo, para verificar se um usuário tem mais de 18 anos) já está na resposta dada por @blowdart ( https://stackoverflow.com/a/31465227/4974715 ).
PS: Eu digitei isso no meu telefone. Perdoe quaisquer erros de digitação e falta de formatação.
fonte