Percebo que a segurança do Spring se baseia na cadeia de filtros, que interceptará a solicitação, detectará (ausência de) autenticação, redirecionará para o ponto de entrada da autenticação ou passará a solicitação para o serviço de autorização e, eventualmente, permitirá que a solicitação atinja o servlet ou gere uma exceção de segurança (não autenticado ou não autorizado). DelegatingFitlerProxy cola esses filtros juntos. Para executar suas tarefas, esses serviços de acesso ao filtro, como UserDetailsService e AuthenticationManager .
Os principais filtros da cadeia são (na ordem)
- SecurityContextPersistenceFilter (restaura a autenticação de JSESSIONID)
- UsernamePasswordAuthenticationFilter (executa autenticação)
- ExceptionTranslationFilter (capturar exceções de segurança de FilterSecurityInterceptor)
- FilterSecurityInterceptor (pode gerar exceções de autenticação e autorização)
Estou confuso como esses filtros são usados. Será que para o formulário fornecido na primavera, o UsernamePasswordAuthenticationFilter é usado apenas para / login e os filtros posteriores não? O elemento do espaço para nome do formulário-login configura automaticamente esses filtros? Todas as solicitações (autenticadas ou não) chegam ao FilterSecurityInterceptor para obter um URL sem logon?
E se eu quiser proteger minha API REST com o token JWT , que é recuperado do login? Preciso configurar duas http
tags de configuração de namespace , direitos? Um para / login com UsernamePasswordAuthenticationFilter
e outro para URLs REST, com customização JwtAuthenticationFilter
.
A configuração de dois http
elementos cria dois springSecurityFitlerChains
? Está UsernamePasswordAuthenticationFilter
desativado por padrão, até que eu declare form-login
? Como faço para substituir SecurityContextPersistenceFilter
com um filtro que irá obter Authentication
a partir existente JWT-token
em vez de JSESSIONID
?
fonte
Respostas:
A cadeia de filtros de segurança Spring é um mecanismo muito complexo e flexível.
Examinando a documentação atual do release estável 4.2.1 , seção 13.3 Ordenação de filtros, você pode ver toda a organização de filtros da cadeia de filtros:
Agora, tentarei continuar suas perguntas uma a uma:
Depois de configurar um
<security-http>
seção, para cada uma você deve fornecer pelo menos um mecanismo de autenticação. Esse deve ser um dos filtros que correspondem ao grupo 4 na seção 13.3 Ordenação de filtros da documentação do Spring Security que acabei de referenciar.Este é o elemento http mínimo de segurança válido: que pode ser configurado:
Ao fazer isso, esses filtros são configurados no proxy da cadeia de filtros:
Nota: Eu os obtenho criando um RestController simples que @Autowires the FilterChainProxy e retorna seu conteúdo:
Aqui pudemos ver que apenas declarando o
<security:http>
elemento com uma configuração mínima, todos os filtros padrão estão incluídos, mas nenhum deles é do tipo Autenticação (quarto grupo na seção 13.3 Ordenação de filtros). Portanto, na verdade, significa que apenas declarando osecurity:http
elemento, o SecurityContextPersistenceFilter, o ExceptionTranslationFilter e o FilterSecurityInterceptor são configurados automaticamente.De fato, um mecanismo de processamento de autenticação deve ser configurado e até os beans de namespace de segurança processam reivindicações para isso, gerando um erro durante a inicialização, mas isso pode ser ignorado pela adição de um atributo de ponto de entrada-ref em
<http:security>
Se eu adicionar um básico
<form-login>
à configuração, desta maneira:Agora, o filterChain ficará assim:
Agora, esses dois filtros org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter e org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter são criados e configurados no FilterChainProxy.
Então, agora, as perguntas:
Sim, é usado para tentar concluir um mecanismo de processamento de login, caso a solicitação corresponda ao URL UsernamePasswordAuthenticationFilter. Esse URL pode ser configurado ou até alterado seu comportamento para corresponder a todas as solicitações.
Você também pode ter mais de um mecanismo de processamento de autenticação configurado no mesmo FilterchainProxy (como HttpBasic, CAS, etc.).
Não, o elemento form-login configura o UsernamePasswordAUthenticationFilter e, caso você não forneça um URL da página de login, ele também configura o org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter, que termina em um login simples gerado automaticamente página.
Os outros filtros são configurados automaticamente por padrão apenas criando um
<security:http>
elemento semsecurity:"none"
atributo.Cada solicitação deve alcançá-lo, pois é o elemento que cuida se a solicitação tem os direitos de atingir o URL solicitado. Mas alguns dos filtros processados anteriormente podem parar o processamento da cadeia de filtros, simplesmente não sendo chamados
FilterChain.doFilter(request, response);
. Por exemplo, um filtro CSRF pode parar o processamento da cadeia de filtros se a solicitação não tiver o parâmetro csrf.Não, você não é forçado a fazer isso. Você pode declarar ambos
UsernamePasswordAuthenticationFilter
e oJwtAuthenticationFilter
mesmo elemento http, mas isso depende do comportamento concreto de cada um desses filtros. Ambas as abordagens são possíveis e a escolha final depende das próprias preferências.Sim, é verdade
Sim, você pode vê-lo nos filtros criados em cada uma das configurações que publiquei
Você pode evitar o SecurityContextPersistenceFilter, apenas configurando a estratégia de sessão no
<http:element>
. Basta configurar assim:<security:http create-session="stateless" >
Ou, nesse caso, você pode substituí-lo por outro filtro, desta forma dentro do
<security:http>
elemento:EDITAR:
Finalmente, isso depende da implementação de cada filtro em si, mas é verdade que os últimos filtros de autenticação são capazes de sobrescrever qualquer autenticação anterior eventualmente feita pelos filtros anteriores.
Mas isso não acontece necessariamente. Eu tenho alguns casos de produção em serviços REST protegidos, onde eu uso um tipo de token de autorização que pode ser fornecido como um cabeçalho Http ou dentro do corpo da solicitação. Portanto, configurei dois filtros que recuperam esse token, em um caso do cabeçalho Http e o outro no corpo da solicitação da própria solicitação de descanso. É verdade que, se uma solicitação http fornecer esse token de autenticação como cabeçalho Http e dentro do corpo da solicitação, ambos os filtros tentarão executar o mecanismo de autenticação que o delegará ao gerente, mas isso poderá ser facilmente evitado simplesmente verificando se a solicitação está correta. já autenticado apenas no início do
doFilter()
método de cada filtro.Ter mais de um filtro de autenticação está relacionado a ter mais de um provedor de autenticação, mas não o force. No caso exposto anteriormente, tenho dois filtros de autenticação, mas apenas um provedor de autenticação, pois os dois filtros criam o mesmo tipo de objeto de autenticação. Nos dois casos, o gerenciador de autenticação o delega ao mesmo provedor.
E, ao contrário disso, também tenho um cenário em que publico apenas um UsernamePasswordAuthenticationFilter, mas as credenciais do usuário podem estar contidas no DB ou LDAP, por isso tenho dois provedores de suporte de UsernamePasswordAuthenticationToken e o AuthenticationManager delega qualquer tentativa de autenticação do filtro nos provedores para validar as credenciais.
Portanto, acho claro que nem a quantidade de filtros de autenticação determina a quantidade de provedores de autenticação nem a quantidade de provedor determina a quantidade de filtros.
Eu não examinei cuidadosamente esse filtro antes, mas após sua última pergunta, estive verificando sua implementação e, como normalmente no Spring, quase tudo poderia ser configurado, estendido ou substituído.
O SecurityContextPersistenceFilter delega em uma implementação SecurityContextRepository a procura pelo SecurityContext. Por padrão, um HttpSessionSecurityContextRepository é usado, mas isso pode ser alterado usando um dos construtores do filtro. Portanto, pode ser melhor escrever um SecurityContextRepository que atenda às suas necessidades e apenas configurá-lo no SecurityContextPersistenceFilter, confiando no seu comportamento comprovado, em vez de começar a fazer tudo do zero.
fonte
No qualifying bean of type 'org.springframework.security.web.FilterChainProxy' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
Não,
UsernamePasswordAuthenticationFilter
estendeAbstractAuthenticationProcessingFilter
, e isso contém aRequestMatcher
, o que significa que você pode definir seu próprio URL de processamento, esse filtro manipula apenas asRequestMatcher
correspondências com o URL de solicitação, o URL de processamento padrão é/login
.Os filtros posteriores ainda podem manipular a solicitação, se a
UsernamePasswordAuthenticationFilter
execução for executadachain.doFilter(request, response);
.Mais detalhes sobre instaladores principais
UsernamePasswordAuthenticationFilter
é criado por<form-login>
, são Aliases de filtro padrão e PedidosDepende se os adaptadores anteriores são bem-sucedidos, mas
FilterSecurityInterceptor
é o último ajustador normalmente.Sim, todo fitlerChain tem um
RequestMatcher
, se oRequestMatcher
corresponder à solicitação, a solicitação será tratada pelos instaladores na cadeia de montagem.O padrão
RequestMatcher
corresponde a todas as solicitações se você não configurar o padrão ou pode configurar o URL específico (<http pattern="/rest/**"
).Se você quiser saber mais sobre os instaladores, acho que você pode verificar o código-fonte na segurança da primavera.
doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain)
fonte
Spring security é uma estrutura baseada em filtro, ele planta um WALL (HttpFireWall) antes da sua aplicação em termos de filtros proxy ou beans gerenciados por primavera. Sua solicitação precisa passar por vários filtros para acessar sua API.
Sequência de execução no Spring Security
WebAsyncManagerIntegrationFilter
Fornece integração entre o SecurityContext e o WebAsyncManager do Spring Web.SecurityContextPersistenceFilter
Esse filtro será executado apenas uma vez por solicitação, preenche o SecurityContextHolder com informações obtidas do SecurityContextRepository configurado antes da solicitação e as armazena de volta no repositório assim que a solicitação for concluída e limpar o detentor do contexto.A solicitação é verificada para a sessão existente. Se uma nova solicitação, SecurityContext será criada, caso contrário, se a solicitação tiver sessão, o contexto de segurança existente será obtido no repositório .
HeaderWriterFilter
Filtre a implementação para adicionar cabeçalhos à resposta atual.LogoutFilter
Se o pedido url é/logout
(para a configuração padrão) ou se mathces pedido de URLRequestMatcher
configurado emLogoutConfigurer
seguida,LogoutConfigurer
/
ou URL de sucesso de logout configurado ou chama logoutSuccessHandler configurado.UsernamePasswordAuthenticationFilter
HTTP POST
) padrão/login
ou correspondências.loginProcessingUrl()
configuradas emFormLoginConfigurer
seguida,UsernamePasswordAuthenticationFilter
tentará a autenticação.usernameParameter(String)
,passwordParameter(String)
..loginPage()
substitui os padrõesAuthentication
objeto (UsernamePasswordAuthenticationToken
ou qualquer implementação deAuthentication
no caso do seu filtro de autenticação personalizado) é criado.authenticationManager.authenticate(authToken)
será invocadoAuthenticationProvider
métodos de autenticação, tente todos os provedores de autenticação e verifique qualquersupports
objeto de provedor de autenticação authToken / authentication, o provedor de autenticação de suporte será usado para autenticação. e retorna o objeto de autenticação em caso de autenticação bem-sucedida lançadaAuthenticationException
.authenticationSuccessHandler
invocada, o redirecionamento para o URL de destino configurado (o padrão é/
)SecurityContextHolderAwareRequestFilter
, se você estiver usando-o para instalar um HttpServletRequestWrapper compatível com o Spring Security no contêiner do servletAnonymousAuthenticationFilter
Detecta se não há nenhum objeto de autenticação no SecurityContextHolder, se nenhum objeto de autenticação encontrado, criaAuthentication
object (AnonymousAuthenticationToken
) com autoridade concedidaROLE_ANONYMOUS
. AquiAnonymousAuthenticationToken
facilita a identificação de solicitações subseqüentes de usuários não autenticados.ExceptionTranslationFilter
, para capturar quaisquer exceções do Spring Security para que uma resposta de erro HTTP possa ser retornada ou um AuthenticationEntryPoint apropriado possa ser iniciadoFilterSecurityInterceptor
Haverá o
FilterSecurityInterceptor
que vem quase por último na cadeia de filtros que obtém o objeto AutenticaçãoSecurityContext
e recebe a lista de autoridades concedidas (funções concedidas) e tomará uma decisão para permitir que essa solicitação atinja o recurso solicitado ou não, a decisão é tomada por correspondência com o permitidoAntMatchers
configurado emHttpSecurityConfiguration
.Considere as exceções 401-Não autorizado e 403-Proibido. Essas decisões serão tomadas no final da cadeia de filtros
Nota: Request usuário flui não só na acima filtros mencionado, mas há outros filtros também não mostrados aqui (.
ConcurrentSessionFilter
,RequestCacheAwareFilter
,SessionManagementFilter
...)Será diferente quando você usa o filtro de autenticação personalizada em vez de
UsernamePasswordAuthenticationFilter
.Será diferente se você configurar o filtro de autenticação JWT e omitir que
.formLogin() i.e, UsernamePasswordAuthenticationFilter
ele se tornará um caso totalmente diferente.Somente para referência. Filtros no spring-web e spring-security
Nota: consulte o nome do pacote na foto , pois existem outros filtros do orm e do meu filtro implementado personalizado.
Você também pode consultar a
maneira mais comum de autenticar um aplicativo Web moderno?
diferença entre autenticação e autorização no contexto do Spring Security?
fonte