Este artigo entende como os filtros e interceptores funcionam por meio de uma simples prática de desenvolvimento de certificação de segurança.
Muitos artigos associam filtros, interceptores e ouvintes ao Spring para explicar, e acreditam que filtros, interceptores e ouvintes são funções de componentes amplamente usadas fornecidas pela primavera.
Mas, estritamente falando, filtros e ouvintes pertencem à API do servlet e não têm nada a ver com a primavera.
Como o filtro herda da interface javax.servlet.filter e o ouvinte herda da interface javax.servlet.servletContextListener, apenas o interceptor herda a interface org.springframework.web.servlet.HandlerIntercetor.
O fluxograma acima é referenciado a partir das informações on -line e uma imagem vale mais que mil palavras. Depois de ler este artigo, você terá uma compreensão mais profunda do processo de chamada de filtros e interceptores.
1. Idéias de design de certificação de segurança
Às vezes, quando redes internas e externas chamam APIs, os requisitos de segurança para requisitos diferentes. Em muitos casos, as várias restrições em redes externas chamam APIs não são necessárias na intranet. No entanto, ao implantar gateways, as APIs a serem chamadas por redes internas e externas podem ser implantadas juntas devido a problemas de custo e complexidade.
Para realizar a segurança da interface restante, isso pode ser feito através de estruturas maduras, como a Spring Security ou Shiro.
No entanto, como as estruturas de segurança geralmente são complexas (contei a segurança da primavera, existem cerca de 11 módulos principais e a quantidade de código -fonte de Shiro também é incrível). Ao mesmo tempo, configurações complexas podem ser introduzidas (pode fazer com que as pessoas se sintam mais agradáveis), o que não é propício ao desenvolvimento flexível e rápido, implantação e investigação de problemas de equipes pequenas e médias.
Muitas equipes constroem suas próprias rodas para obter a certificação de segurança. Este exemplo de certificação simples neste artigo refere-se à antiga equipe de desenvolvimento de fábricas onde estou e pode ser considerado um serviço de certificação de segurança baseado em token.
A idéia geral de design é a seguinte:
1. Personalize o cabeçalho da solicitação HTTP. Cada vez que a API é chamada, um valor de token é passado no cabeçalho da solicitação.
2. Coloque o token no cache (como Redis) e defina o tempo de expiração de diferentes políticas de acordo com diferentes negócios e APIs.
3. O token pode definir listas de brancos e listas negras, o que pode limitar a frequência das chamadas da API, facilitar o desenvolvimento e o teste, facilitar o manuseio de emergência de anormalidades e até fechar temporariamente a API.
4. A chamada de rede externa deve ser enviada token. O token pode estar relacionado ao usuário, como cada vez que você abrir a página ou fazer login para gerar um cabeçalho de solicitação de gravação de token, a página verifica a validade de cookies e tokens, etc.
Existem dois conceitos na estrutura de segurança da primavera, a saber, autenticação e autorização . Autenticação refere -se a usuários que podem acessar o sistema, enquanto a autorização é um recurso que os usuários podem acessar.
Para atingir os requisitos de autenticação de segurança simples acima, pode ser necessário criar independentemente um serviço de token para garantir que o token seja globalmente único. Os módulos que podem incluir geradores de fluxo personalizados, CRM, criptografia e descriptografia, logs, estatísticas da API, caches, etc., mas eles estão realmente fracamente ligados aos usuários (CRM). Alguns serviços públicos relacionados a usuários, como SMS e serviços de email que costumamos usar, também podem resolver chamadas de segurança através do mecanismo de token.
Em resumo, a certificação simples de segurança neste artigo é um pouco diferente da autenticação e autorização fornecidas pela estrutura de segurança da primavera. Obviamente, esse método de tratamento de "segurança" não é novo para os profissionais, mas pode bloquear um grande número de usuários iniciantes do lado de fora.
2. Personalize o filtro
Similar to Spring MVC, Spring Boot provides many servlet filters (Filters) to use, and it automatically adds some commonly used filters, such as CharacterEncodingFilter (used to handle encoding problems), HiddenHttpMethodFilter (hidden HTTP function), HttpPutFormContentFilter (form form processing), RequestContextFilter (request context), etc. Usually we will also customize Filter to implement Algumas funções comuns, como registro de registros, determinar se devem fazer login, verificação de permissão, etc.
1. Cabeçalho de solicitação personalizado
É muito simples, adicione um cabeçalho de solicitação personalizado AuthToken no cabeçalho da solicitação:
@RequestMapping (value = "/getinfobyid", método = requestMethod.post) @apioperation ("Consulta as informações do produto com base no ID do produto") @apiimplicitParams ({@apiimplicticparam (paramtype = "header", nome = "auttonypy", requery = true, value = "autytanky" ",", name = "AuthToken", exigido = True, " GetgoodsbygoodsidResponse getgoodsbygoodsid (@RequestHeader String authToken, @RequestBody getgoodsbygoodsidRequest request) {return _goodsapiservice.getgoodsbygoodsid (request); } getgoodsbygoodsidO campo AuthToken modificado pelo @RequestHeader pode ser exibido em uma estrutura como Swagger.
Após ligar, você pode ver o cabeçalho da solicitação de acordo com a ferramenta HTTP. O exemplo deste artigo é AuthToken (diferente do token de algumas estruturas):
NOTA: Muitas ferramentas HTTPClient suportam cabeçalhos de solicitação de transmissão dinâmica, como Resttemplate.
2. Implementar filtro
Existem três métodos na interface do filtro, ou seja, init, Dofilter e Destory. Quando você vir o nome, provavelmente conhecerá seus principais usos. Geralmente, precisamos apenas processar solicitações HTTP dentro do método Dofilter:
pacote com.power.demo.controller.filter; importar com.power.demo.common.appconst; importar com.power.demo.common.bizresult; import com.power.demo.service.conttract.authTokenService; import com.em.Demo.utilPower.port; org.springframework.beans.factory.annotation.autowired; importar org.springframework.tereotype.component; importar javax.servlet.*; importar javax.servlet.http.httpsTleTreChest; importar java.io.ioException; AuthTokenservice AuthTokenservice; @Override public void init (FilterConfig var1) lança servletexception {} @Override public void Dofilter (Solicitação de servletRequest, resposta servletResponse, cadeia de filtragem) lança IoException, servletexcept {htttpSleTreQuest Req = (HTTStTrelestRerestrestlest); String token = req.getheader (appConnst.auth_token); BizResult <String> bizResult = authTokenservice.powerCheck (token); System.out.println (Serializeutil.Serialize (BizResult)); if (bizResult.getISOK () == true) {PowerLogger.info ("filtro de token de autenticação aprovado"); Chain.Dofilter (solicitação, resposta); } else {lança nova servletexception (bizresult.getMessage ()); }} @Override public void Destro () {}} AuthTokenFilterObserve que, da perspectiva da hierarquia real, a maioria das coisas que processam mais camadas de expressão são processadas. Não é recomendável usar diretamente a camada de acesso a dados no filtro. Embora eu tenha visto esse código muitas vezes em muitos projetos antigos antigos há um ou dois anos, e há precedentes para escrever dessa maneira no livro << prática da primavera >>.
3. Serviço de certificação
Esta é a principal lógica de negócios. O código de exemplo é apenas uma maneira simples de anotar idéias e não deve ser usada facilmente em ambientes de produção:
package com.power.demo.service.impl;import com.power.demo.cache.PowerCacheBuilder;import com.power.demo.common.BizResult;import com.power.demo.service.contract.AuthTokenService;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.tereotype.component; importar org.springframework.util.stringutils; @comPonentPublic Classe authTokenServiceImpl implementa AuthTokenservice {@AUTOWIRED PowerCacheBuilder CacheBuilder; / * * Verifique se o token do cabeçalho da solicitação é legal * */ @Override public bizResult <string> PowerCheck (string token) {BizResult <String> bizResult = new BizResult <> (true, "verificação passada"); System.out.println ("O valor de Token é:" + token); if (stringutils.isEmpty (token) == true) {bizresult.setfail ("authToken está vazio"); retornar bizResult; } // Processando Blacklist bizResult = checkforbidlist (token); if (bizResult.getisok () == false) {return bizResult; } // Processando a lista de permissões BizResult = checkLlowList (token); if (bizResult.getisok () == false) {return bizResult; } String key = string.format ("Power.authTokenservice.%S", token); //cachebuilder.set(key, token); //cachebuilder.set(key, token.touppercase ()); // Fetch String existkOken do cache = cachebuilder.get (key); if (stringUtils.isEmpty (existkoken) == true) {bizresult.setfail (string.format ("this authToken:%s", token)); retornar bizResult; } // Compare se o token é o mesmo booleano isequal = token.equals (existkoken); if (isequal == false) {bizresult.setfail (string.format ("ilegal authToken:%s", token)); retornar bizResult; } // Faça algo retornar bizResult; }} AuthTokenserviceImplVocê pode consultar o serviço de cache que você usa aqui, que também é um resumo da minha experiência na fábrica anterior.
4. Filtro de registro
Existem duas maneiras comuns de escrever:
(1) Use a anotação @webfilter para identificar o filtro
@Order (1) @webfilter (urlpatterns = {"/api/v1/bens/*", "/api/v1/userinfo/*"}) public class AuthTokenFilter implementa filtro {Usando a anotação @Webfilter, você também pode usar a anotação @Order em conjunto com a anotação @Order. A anotação @Order representa a ordem de filtragem. Quanto menor o valor, mais você o executa primeiro. Esse tamanho de pedido é tão útil quanto o processamento do ciclo de vida das solicitações HTTP durante nosso processo de programação. Obviamente, se a ordem não for especificada, a ordem do filtro é chamada oposta à ordem dos filtros adicionados e a implementação do filtro é o padrão da cadeia de responsabilidade.
Por fim, adicione a anotação @ServletConentsCan à classe de inicialização para usar o filtro personalizado normalmente.
(2) Use o FilterRegistrationBean para personalizar o registro de filtro
Este artigo usa a segunda implementação para implementar o registro de filtro personalizado:
pacote com.power.demo.controller.filter; importar com.google.common.collect.lists; importar org.springframework.beans.factory.annotation.autowired; importation.springframework.boot.web.servlet.FilterTexTerTationBeanBeanBean; org.springframework.context.annotation.configuration; importar org.springframework.tereotype.component; importar java.util.list;@configature@componentpublic class RestFilterConfig {@Autowired Private AuthTokenFilter Filter; @Bean public filterRegistrationBean filterRegistrationBean () {filterRegistrationBean registroBean = new FilterRegistrationBean (); registroBean.setFilter (filtro); // SET (Fuzzy) Matching URL List <String> urlpatterns = lists.newArrayList (); urlpatterns.add ("/api/v1/bens/*"); urlpatterns.add ("/api/v1/userinfo/*"); RegistrationBean.SeturlPatterns (URLPatterns); RegistrationBean.setorder (1); registroBean.setEnabled (true); retornar registroBean; }} RestFilterConfigPor favor, preste atenção especial aos urlpatterns. O atributo URLPatterns especifica o padrão de URL a ser filtrado. Este parâmetro é de grande importância para a área de ação do filtro.
Registre o filtro e, quando a inicialização do spring iniciar, ele adicionará automaticamente a cadeia de chamadas de filtro ApplicationFilterchain quando detectar um feijão com javax.servlet.filter.
Ligue para uma API para tentar o efeito:
Geralmente, personalizamos um aprimoramento global de gerenciamento de exceção unificada GlobalexceptionHandler no Spring Boot (será um pouco diferente do acima).
De acordo com minha prática, as exceções lançadas no filtro não serão capturadas e processadas pelo aprimoramento global de gerenciamento de exceções exclusivas. Isso é diferente do inteceptor interceptador e do interceptador AOP personalizado introduzido no próximo artigo.
Neste ponto, um simples serviço de autenticação de segurança implementado através do filtro personalizado é feito.
3. Interceptor personalizado
1. Implemente o interceptador
Herdar o manipulador de interface e implementar o interceptador. Os métodos de interface são os seguintes:
Prehandle é executado antes da execução da solicitação
Postanha é o fim da execução da solicitação
O pós -conclusão é executado após a conclusão da renderização da visão
pacote com.power.demo.controller.intercept; importar com.power.demo.common.appconst; importar com.power.demo.common.bizresult; import com.power.demo.service.conttract.authtokenservice; import com.em.Demo.utilPower.port.portLogger.port.authTokTokTice; import.Em.EmOmer.UtilPower; org.springframework.beans.factory.annotation.autowired; importar org.springframework.tereotype.component; importar org.springframework.web.servlet.HandlerIntercetor; Importocring.springwork.WEB.Mervlet.ModlandView; javax.servlet.http.httpServletResponse;/ * * token de autenticação interceptador * */ @componentPublic Classe AuthTokenInterceptor implementa HandlerIntercept {@AUTOWIRED AUTHTOKENSERVICE AUTHTOKENSERVICE; / * * Execute antes da solicitação Execução * */ @Override public boolean prehandle (solicitação httpServletRequest, resposta httpServletResponse, manipulador de objeto) lança exceção {boolean handleResult = false; String token = request.getheader (appconst.auth_token); BizResult <String> bizResult = authTokenservice.powerCheck (token); System.out.println (Serializeutil.Serialize (BizResult)); handleResult = bizResult.getisok (); PowerLogger.Info ("Auth token interceptador interceptador interceptador interceptador interceptador interceptador interceptador interceptor Passado"); } else {lança nova exceção (bizresult.getMessage ()); } retornar HandleResult; } /* * The request ends execution* */ @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } /* * Execute after view rendering is completed* */ @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object manipulador, exceção ex) lança Exceção {}} AuthTokenInterceptorNo exemplo, optamos por executar a autenticação de segurança de token antes que a solicitação seja executada.
O Serviço de Autenticação é o AuthTokenservice introduzido no filtro e a camada lógica de negócios é reutilizada.
2. Registre o interceptador
Defina uma classe InterceptConfig, herdada do WebMVCConfiguraçõespport, e o WebMVCConfigureRAdApter está desatualizado.
Injete o AuthTokenInterceptor como feijão, os URLs e filtros que outras configurações interceptor Intercept são muito semelhantes:
package com.power.demo.controller.interceptor;import com.google.common.collect.Lists;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.stereotype.Component;import org.springframework.web.servlet.config.annotation.defaultServleThandlerConfigurer; importar org.springframework.web.servlet.config.annotation.intercetorRegistry; import org.springframework.web.Servlet.Conftation.Onnotation.Onnotation.InnOnging.onnOng.onnotation.onnotation.intercetorRegistry; importar org.springframework.web.Servlet.Confulation.onnotation.onnotation.interCorgistry; importação; org.springframework.web.servlet.config.annotation.webmvcconfigurationsupport; importar java.util.list;@configature@componentpublic stractOnTOnFigRAdRAndEnds WebMVCConfigurationSuport {// webmvcconfigRAdRAdRAdRAdRAdRAdRAdRAdRAdRAdRAdTerTends) "/favicon.ico"; /*** Constatou que, se o WebMVCConfigurationSupport for herdado, o conteúdo relevante configurado no YML será inválido. * *@param Registry */@Override public void addResourceHandlers (Recurso -HandlerRegistry Registry) {Registry.addResourceHandler ("/"). AddResourcelocations ("/**"); Registry.addResourceHandler ("/static/**"). AddResourCelocations ("ClassPath:/static/"); } / *** Configure o processamento do servlet* / @Override public void configulefaultServLetHandling (defaultServLetHandlerConfigurer Configure) {configurer.enable (); } @Override public void addinterceptores (Registro de InterceptorRegistry) {// set (Fuzzy) Matching URL List <String> urlpatterns = lists.newArrayList (); urlpatterns.add ("/api/v1/bens/*"); urlpatterns.add ("/api/v1/userinfo/*"); Registry.AddIntercept (AuthTokenInterceptor ()). AddPathPatterns (UrlPatterns) .ExcludEPathPatterns (Favicon_url); super.addinterceptores (Registro); } // Escreva o interceptador como um feijão na configuração @Bean public AuthTokenInterceptor AuthTokenInterceptor () {return new AuthTokenInterceptor (); }} InterceptConfigDepois de iniciar o aplicativo, você pode ver o efeito da interceptação interceptadora chamando a interface. Global Unified Exception Management GlobalexceptionHandler lida com as seguintes exceções depois de pegá -las:
É quase o mesmo que a principal mensagem de erro exibida pelo filtro, mas as informações da pilha são mais ricas.
4. A diferença entre filtro e interceptador
As principais diferenças são as seguintes:
1. Os interceptores são baseados principalmente no mecanismo de reflexão de Java, enquanto os filtros são baseados em retornos de chamada de função
2. O Interceptor não depende do contêiner de servlet, os filtros dependem do contêiner de servlet
3. Os interceptores só podem trabalhar em solicitações de ação, enquanto os filtros podem trabalhar em quase todas as solicitações.
4. O interceptador pode acessar o objeto no contexto de ação e na pilha de valor, mas o filtro não pode acessá -lo.
5. Durante o ciclo de vida de uma ação, o interceptador pode ser chamado várias vezes, enquanto o filtro só pode ser chamado uma vez quando o contêiner é inicializado.
Alguns artigos que referenciei disseram que "o interceptador pode obter vários feijões no contêiner do COI, mas o filtro não pode. Isso é muito importante. Injetar um serviço no interceptador pode chamar a lógica de negócios". Após a verificação real, isso está errado.
NOTA: O tempo de acionamento do filtro é após o contêiner e antes do servlet; portanto, o parâmetro de entrada do Dofilter do filtro (Solicitação de ServletRequest, Resposta do ServletResponse, Cadeia de Filtro) é servletRequest, não httpServletRequest, porque o filtro é antes do HttPSEVLET. A figura a seguir pode fornecer uma compreensão mais intuitiva do tempo de execução do filtro e do interceptador:
Somente solicitações aprovadas pelo DispatcheserServlet serão seguidas pela cadeia interceptadora. As solicitações de servlet personalizadas não serão interceptadas. Por exemplo, nosso endereço de servlet personalizado http: // localhost: 9090/testServlet não será interceptado pelo interceptador. Mas não importa a qual servlet ele pertence, o filtro será executado desde que esteja em conformidade com as regras do filtro do filtro.
De acordo com a análise acima, entender o princípio será simples, mesmo os filtros ASP.NET serão os mesmos.
Problema: alcançar uma autenticação de segurança mais flexível
Na Web Java, através do filtro personalizado ou do interceptador interceptador, a autenticação segura de APIs de correspondência específicas podem ser alcançadas, como a correspondência de todas as APIs, a correspondência de uma ou várias APIs etc., mas às vezes esse padrão correspondente não é relativamente amigável aos desenvolvedores.
Podemos nos referir à segurança da primavera para obter funções poderosas por meio da anotação + Spel.
Por exemplo, no ASP.NET, geralmente usamos o recurso autorizado, que pode ser adicionado a classes ou aplicado a métodos, e podemos controlar a autenticação de segurança de maneira mais dinâmica e flexível.
Não escolhemos a segurança da primavera, para que possamos implementar a certificação de segurança flexível semelhante à autorizada. A principal tecnologia de implementação é a AOP com a qual estamos familiarizados.
O conhecimento básico de alcançar uma interceptação mais flexível através do método AOP não será mencionado neste artigo. Mais tópicos sobre a AOP serão compartilhados no próximo artigo.
Resumir
O exposto acima é o que o editor apresentou a você. O Spring Boot usa filtros e interceptores para obter autenticação simples e segura de interfaces de repouso. Espero que seja útil para todos. Se você tiver alguma dúvida, deixe -me uma mensagem e o editor responderá a todos a tempo. Muito obrigado pelo seu apoio ao site wulin.com!