origem
No RABC padrão, as permissões precisam suportar a configuração dinâmica, os padrões de segurança da primavera para concordar com as permissões no código. Os cenários de negócios reais geralmente exigem que as permissões de acesso à função sejam configuradas dinamicamente, ou seja, para configurar as funções de acesso correspondentes aos URLs em tempo de execução.
Com base na segurança da primavera, como atingir esse requisito?
A maneira mais fácil é personalizar um filtro para concluir o julgamento da permissão, mas isso é separado da estrutura de segurança da primavera. Como implementá -lo elegantemente com base na segurança da primavera?
Revisão da Autorização de Segurança da Primavera
O filtro de segurança da primavera FilterChainProxy é usado como um filtro para se registrar na Web. FilterChainProxy contém vários filtros internos de uma só vez. Primeiro, precisamos entender os vários filtros incorporados em segurança da primavera:
| Alias | Classe de filtro | Elemento de namespace ou atributo |
|---|---|---|
| Canal_filter | ChannelProcessingFilter | http/intercept-url@requer canal |
| Security_context_filter | SecurityContextPerSistenceFilter | http |
| Concurrent_session_filter | ConcurrentSessionFilter | Gestão da sessão/CONTROLO DE CONCURREÇÃO |
| Headers_filter | HeaderWriterFilter | http/cabeçalhos |
| CSRF_FILTER | CSRffilter | HTTP/CSRF |
| Logout_filter | LogoutFilter | http/logout |
| X509_filter | X509AuthenticationFilter | http/x509 |
| Pre_auth_filter | ResumoPreauthenticatedProcessingFilter Subclasses | N / D |
| Cas_filter | CasauthenticationFilter | N / D |
| Form_login_filter | UsernamePasswordAthenticationFilter | http/form-logina |
| Basic_auth_filter | BasicAuthenticationFilter | http/http-basic |
| Servlet_api_support_filter | SecurityContextholderAWARereQuestFilter | http/@servlet-api-provision |
| JAAS_API_SUPPORT_FILTER | JaasapiintegrationFilter | http/@jaas-api-provision |
| LEMBRE_ME_FILTER | Lembre -se de filter | http/lembre-me |
| Anonymous_filter | AnonyMousAuthenticationFilter | http/anônimo |
| Session_management_filter | SessionManagementFilter | Gestão da sessão |
| Exception_translation_filter | ExceptionTranslationFilter | http |
| Filtro_security_intercept | FilterSecurityInterceptor | http |
| Switch_user_filter | SwitchUserFilter | N / D |
O mais importante é o FilterSecurityInterceptor, que implementa a lógica principal de autenticação, e o código mais central está aqui:
InterceptStatustoken protegido antes da vocação (objeto) {// Obtenha as permissões necessárias para acessar a coleção de URL <Figattribute> atributos = this.obtainSecurityMetadAtAsource () .getAttributes (object); Autenticação autenticada = autenticateIfRequired (); // Autenticação via AccessDecisionManager try {this.accessDecisionManager.Docide (autenticado, objeto, atributos); } catch (accessdeniedException accessdeniedException) {publishEvent (new AuthorizationFailureEvent (objeto, atributos, autenticado, accessdeniedException)); lançar accessdeniedException; } if (debug) {logger.debug ("autorização bem -sucedida"); } if (publicathaThorizationsuccessful ");} if (publicathauthorizationsuccess) {publishEvent (new AuthorizedEvent (objeto, atributos, autenticado);} // tenta ser executado como uma autenticação de usuário diferente; {Logger.debug ("RunasManager não alterou o objeto de autenticação"); SecurityCotexer.getContext (); }Como pode ser visto no exposto, para obter autenticação dinâmica, podemos começar de dois aspectos:
Vamos ver como implementá -lo separadamente.
AccessDecisionManager personalizado
Os três managadores oficiais de AccessDecision são todos baseados no AccessDecisionVoter para implementar a autenticação de permissão, por isso precisamos apenas personalizar um AccessDecisionVoter.
A personalização implementa principalmente a interface AccessDecisionVoter. Podemos implementar um seguimento do Rolevoter oficial:
classe pública RoleBasedVoter implementa AccessDecisionVoter <Becut> {@Override public boolean supports (attribute configattribute) {return true; } @Override public int vote (autenticação de autenticação, objeto, objeto, coleta <configattribute> atributos) {if (autenticação == null) {return Access_denied; } int resultado = access_abstain; Coleção <? estende a concessão de autoridade> autoridades = extrações (autenticação); for (configattribute attribute: atributes) {if (attribute.getAttribute () == null) {continuação; } if (this.supports (attribute)) {resultado = access_denied; // tentam encontrar uma autoridade concedida correspondente para (Autoridade concedida da autoridade: autoridades) {if (attribute.getAttribute (). Igual (autoridade.GetaThority ())) {return Access_GrantEd; }}}} Retorne resultado; } Coleção <? estende a concessão concedida> extrações (autenticação de autenticação) {return autentication.Getathorities (); } @Override public boolean suportes (classe clazz) {return true; }}Como adicionar permissões dinâmicas?
O tipo de objeto de objeto em vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) é o filtro e você pode obter o URL da solicitação atual através do getRequesturl:
FILTERINVOCATION fi = (FilterInvocation) Objeto; String url = fi.getRequesturl ();
Portanto, há muito espaço para expansão aqui. Você pode carregá -lo dinamicamente do banco de dados e, em seguida, julgar o configattribute do URL.
Como usar este VoTer de Role -Based? Use o método AccessDecisionManager para personalizar na configuração. Devemos usar o oficial de unanimidade oficial e, em seguida, adicionar o VoTer de base personalizado.
@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(corsFilter, UsernamePasswordAthaThenticationFilter.class) .ExceptionHandling () .AuthenticationEntryPoint (Problemupport) .AccessDeniedHandler (Problemupport) .And () .csrf () .SessionAnGansion (). .and () .authorizerequests () // ACCESSDECIISTE ACCESSDECIGIONAGER .ACCESSDECISIONGERS (AccessDecisionManager ()) .And () .Apply (SecurityConfigArperAdapter ()); } @Bean public AccessDecisionManager AccessDecisionManager () {List <AccessDecisionVoter <? estende objeto >> DecisionVoters = Arrays.asList (new webExpressionVoter (), // new RoleVoter (), new RoleBasedVoter (), new AuthenticatedVoter ()); devolver novos unanimous baseados (DecisionVoters); }Personalize o SecurityMetAdatasource
FilterInvocationSecurity MetAdATASource personalizado só precisa implementar a interface e carregar regras dinamicamente do banco de dados na interface.
Para reutilizar as definições no código, podemos pegar o SecurityMetadATAsource gerado no código e passar no filtro inadimplenteinvocationSecurityMetadAsource no construtor.
classe pública appfilterinvocationsecuritymetadatasource implementa org.springframework.security.web.access.intercept.filterinvocationsecurityMetAdatasource {private filterInvocuryMetAdAdatasource SuperMetadatasource; @Override Public Collection <Figattribute> getAllConfigAttributes () {return null; } public appfilterinvocationsecurityMetadAsource (filterInvocationsecurityMetadatasource ExpressionBasedFilterinvocationsecurityMetadAtAsource) {this.suPerMetadAsource = ExpressionBasedFilterinVococutesMetAsTadasTAdAsource; // TODO LOAD CONFIGURAÇÃO DE PERMISSÃO DO DATABASE} private Final Antpathmatcher Antpathmatcher = new AntPathMatcher (); // Aqui você precisa carregar mapa final privado <string, string> urlrolemap = new hashmap <string, string> () {{put ("/open/**", "role_anonymous"); put ("/saúde", "role_anonymous"); put ("/reiniciar", "role_admin"); put ("/demo", "role_user"); }}; @Override Public Collection <Figattribute> getAttributes (objeto objeto) lança ilegalArgumentException {filterInvocation fi = (filterInvocation) objeto; String url = fi.getRequesturl (); para (map.entry <string, string> Entrada: urlrolemap.entryset ()) {if (AntPathMatcher.match (Entry.getKey (), url)) {return securityConfig.Createlist (Entry.getValue ()); }} // retorna a configuração padrão definida pelo código Return supermetAdataSource.getAttributes (object); } @Override public boolean suporta (classe <?> Clazz) {return filterinvocation.class.isassignablefrom (clazz); }}Como usá -lo? Ao contrário do AccessDecisionManager, o ExpressionUlAuthorizationConfigurer não fornece um método definido para definir o filterInvocationsecurityMetadAtAsource do filterSecurityInterceptor, como fazer?
Descubra um método de extensão WithObjectPostProcessor, através do qual personaliza um objectPostProcessor que lida com o tipo FilterSecurityInterceptor, você pode modificar o filterSecurityInterceptor.
@EnableWebSecurity@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(corsFilter, UsernamePasswordAthaThenticationFilter.class) .ExceptionHandling () .AuthenticationEntryPoint (Problemupport) .AccessDeniedHandler (Problemupport) .And () .csrf () .SessionAnGansion (). .e () .authorizeRequests () // FilterInvocationsCationSecurityMetAdATAdATAsource .WithObjectPostProcessor (new ObjectPostProcessor <FilterSecurityInterceptor> () {@Override public <O FilterSecurityIntercetor> o Postprocess (o FSI) { fsi.setSecurityMetAdatasource (MySecurityMetAdatasource (fsi.getSecurityMetadATAsource ()); } @Bean public AppFilterInvocationsecurityMetAdatasource mySecurityMetadAtAsource (filterInvocationsecurityMetadatasource filtroinvocationsecuryMetadAsource) {AppfilterinvocationsCurityMetadAsource Segurança AppFilterInvocationsecurityMetAdAtAsource (filterInvocationsecurityMetadatasource); Retornar SecurityMetAdATAsource;}resumo
Este artigo apresenta dois métodos para implementar permissões dinâmicas com base na segurança da primavera. Um é personalizar o AccessDecisionManager, e o outro é personalizar o filterInvocationsecurityMetadatasource. Você pode escolher de maneira flexível de acordo com suas necessidades em projetos reais.
Leitura adicional:
Arquitetura de segurança da primavera e análise de código -fonte
Resumir
O acima é o conteúdo inteiro deste artigo. Espero que o conteúdo deste artigo tenha certo valor de referência para o estudo ou trabalho de todos. Se você tiver alguma dúvida, pode deixar uma mensagem para se comunicar. Obrigado pelo seu apoio ao wulin.com.