English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Categorias de uso da spring security:
Como usar a spring security, acredito que todos que pesquisaram no Baidu sabem, há quatro métodos de uso, de mais simples para mais complexo:
1、Não usar o banco de dados, escrever todos os dados no arquivo de configuração, isso também é um demo no documento oficial;
2、Usar o banco de dados, projetar o banco de dados com base no código de implementação padrão da spring security, isso significa que o banco de dados já está fixo, este método não é flexível e o design do banco de dados é muito simples, a utilidade é ruim;
3、A spring security é diferente do Acegi, ela não pode modificar o filtro padrão, mas suporta a inserção de filtros, então com base nisso, podemos inserir nossos próprios filtros para usar de forma flexível;
4、Métodos violentos, modificar o código-fonte, o que foi mencionado anteriormente sobre a modificação do filtro padrão é apenas substituir o filtro através do arquivo de configuração, isso é diretamente modificar o código-fonte, mas isso não é compatível com o princípio de design OO e não é prático, inutilizável.
Este artigo introduz o conteúdo relacionado ao login de autenticação personalizado da spring security, compartilhado para referência e estudo. Não há muito a dizer, vamos ver a introdução detalhada.
1.Resumo
1.1.Introdução
A spring security é uma framework de segurança baseada em Spring AOP e Servlet Filter, usada para gerenciar autenticação de permissões e outros.
1.2.fluxo de autenticação personalizado da spring security
1) Processo de autenticação
Gerar o AuthenticationToken não autenticado
↑(obter informações) (atribuir provider com base no AuthenticationToken) AuthenticationFilter -> AuthenticationManager -> AuthenticationProvider ↓(autenticação) UserDetails (geralmente obtido através da consulta ao banco de dados) ↓(através) Gerar o AuthenticationToken de autenticação bem-sucedida ↓(armazenamento) SecurityContextHolder
2Adicionar o AuthenticationFilter à cadeia de filtros de segurança (configurado no servidor de recursos), por exemplo:
http.addFilterBefore(AuthenticationFilter, AbstractPreAuthenticatedProcessingFilter.class)
ou:
http.addFilterAfter(AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
2.Exemplo de login por SMS com número de telefone
2.1.Ambiente de desenvolvimento
2.2.Análise de código nuclear
2.2.1.Processo de autenticação de login personalizado
2.2.1.1.Token de autenticação de login personalizado
/** * Token de login de telefone celular * * @author : CatalpaFlat */ public class MobileLoginAuthenticationToken extends AbstractAuthenticationToken { private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationToken.class.getName()); private final Object principal; public MobileLoginAuthenticationToken(String mobile) { super(null); this.principal = mobile; this.setAuthenticated(false); logger.info("MobileLoginAuthenticationToken setAuthenticated ->false loading ... "); } public MobileLoginAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) { super(authorities); this.principal = principal; // must use super, as we override super.setAuthenticated(true); logger.info("MobileLoginAuthenticationToken setAuthenticated ->true loading ... "); } @Override public void setAuthenticated(boolean authenticated) {}} if (authenticated) { throw new IllegalArgumentException( "Cannot set this token to trusted - use constructor that takes a list of GrantedAuthority instead"); } super.setAuthenticated(false); } @Override public Object getCredentials() { return null; } @Override public Object getPrincipal() { return this.principal; } @Override public void eraseCredentials() { super.eraseCredentials(); } }
Nota:
setAuthenticated(): determinar se está autenticado
2.2.1.1.Filtro de autenticação personalizado
/** * Filtro de login por SMS * * @author : CatalpaFlat */ public class MobileLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter { private boolean postOnly = true; private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationFilter.class.getName()); @Getter @Setter private String mobileParameterName; public MobileLoginAuthenticationFilter(String mobileLoginUrl, String mobileParameterName, String httpMethod) {}} super(new AntPathRequestMatcher(mobileLoginUrl, httpMethod)); this.mobileParameterName = mobileParameterName; logger.info("MobileLoginAuthenticationFilter carregando ..."); } @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException { if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) { throw new AuthenticationServiceException("Método de autenticação não suportado: " + request.getMethod()); } //obter mobile String mobile = obtainMobile(request); //montar token MobileLoginAuthenticationToken authRequest = new MobileLoginAuthenticationToken(mobile); // Permitir que subclasses definam a propriedade "details" setDetails(request, authRequest); return this.getAuthenticationManager().authenticate(authRequest); } /** * definir informações detalhadas de autenticação */ private void setDetails(HttpServletRequest request, MobileLoginAuthenticationToken authRequest) { authRequest.setDetails(authenticationDetailsSource.buildDetails(request)); } /** * Obter número de telefone */ private String obtainMobile(HttpServletRequest request) { return request.getParameter(mobileParameterName); } public void setPostOnly(boolean postOnly) { this.postOnly = postOnly; } }
Nota:método attemptAuthentication():
2.2.1.1.Personalizar fornecedor de login de autenticação
/** * Fornecedor de autenticação de login por SMS * * @author : CatalpaFlat */ public class MobileLoginAuthenticationProvider implements AuthenticationProvider { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationProvider.class.getName()); @Getter @Setter private UserDetailsService customUserDetailsService; public MobileLoginAuthenticationProvider() { logger.info("MobileLoginAuthenticationProvider carregando ..."); } /** * Autenticação */ @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { //Obtém informações do token encapsulado pelo filtro MobileLoginAuthenticationToken authenticationToken = (MobileLoginAuthenticationToken) authentication; //Obter informações do usuário (autenticação de banco de dados) UserDetails userDetails = customUserDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal()); //não passado if (userDetails == null) { throw new InternalAuthenticationServiceException("Unable to obtain user information"); } //passado MobileLoginAuthenticationToken authenticationResult = new MobileLoginAuthenticationToken(userDetails, userDetails.getAuthorities()); authenticationResult.setDetails(authenticationToken.getDetails()); return authenticationResult; } /** * Segundo o tipo do token, determina qual provedor usar */ @Override public boolean supports(Class<?> authentication) { return MobileLoginAuthenticationToken.class.isAssignableFrom(authentication); } }
Nota:método authenticate()
2.2.1.1.configuração de autenticação de login personalizada
@Configuration(SpringBeanNameConstant.DEFAULT_CUSTOM_MOBILE_LOGIN_AUTHENTICATION_SECURITY_CONFIG_BN) public class MobileLoginAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> { private static final Logger logger = LoggerFactory.getLogger(MobileLoginAuthenticationSecurityConfig.class.getName()); @Value("${login.mobile.url}") private String defaultMobileLoginUrl; @Value("${login.mobile.parameter}") private String defaultMobileLoginParameter; @Value("${login.mobile.httpMethod}") private String defaultMobileLoginHttpMethod; @Autowired private CustomYmlConfig customYmlConfig; @Autowired private UserDetailsService customUserDetailsService; @Autowired private AuthenticationSuccessHandler customAuthenticationSuccessHandler; @Autowired private AuthenticationFailureHandler customAuthenticationFailureHandler; public MobileLoginAuthenticationSecurityConfig() { logger.info("MobileLoginAuthenticationSecurityConfig loading ..."); } @Override public void configure(HttpSecurity http) throws Exception { MobilePOJO mobile = customYmlConfig.getLogins().getMobile(); String url = mobile.getUrl(); String parameter = mobile.getParameter().getMobile(); String httpMethod = mobile.getHttpMethod(); MobileLoginAuthenticationFilter mobileLoginAuthenticationFilter = new MobileLoginAuthenticationFilter(StringUtils.isBlank(url) ? urlMobileLoginPadrao : url, StringUtils.isBlank(parametro) ? urlMobileLoginPadrao : parametro, StringUtils.isBlank(httpMethod) ? metodoHttpPadraoMobileLogin : httpMethod); mobileLoginAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); mobileLoginAuthenticationFilter.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler); mobileLoginAuthenticationFilter.setAuthenticationFailureHandler(customAuthenticationFailureHandler); MobileLoginAuthenticationProvider mobileLoginAuthenticationProvider = new MobileLoginAuthenticationProvider(); mobileLoginAuthenticationProvider.setCustomUserDetailsService(customUserDetailsService); http.autenticacaoFornecedor(mobileLoginAuthenticationProvider) .adicionarFiltroDepois(mobileLoginAuthenticationFilter, UsernamePasswordAuthenticationFilter.class); } }
Nota:método configure()}
Instanciar AuthenticationFilter e AuthenticationProvider
Adicionar AuthenticationFilter e AuthenticationProvider ao Spring Security.
2.2.2.Verificação de código de verificação personalizado com base no Redis
2.2.2.1.Filtro de código de verificação personalizado com base no Redis
/** * Filtro de código de verificação * * @author : CatalpaFlat */ @Component(SpringBeanNameConstant.DEFAULT_VALIDATE_CODE_FILTER_BN) public class ValidateCodeFilter extends OncePerRequestFilter implements InitializingBean { private static final Logger logger = LoggerFactory.getLogger(ValidateCodeFilter.class.getName()); @Autowired private CustomYmlConfig customYmlConfig; @Autowired private RedisTemplate<Object, Object> redisTemplate; /** * Classe utilitária para verificar se a URL da solicitação coincide com a URL configurada */ private AntPathMatcher pathMatcher = new AntPathMatcher(); public ValidateCodeFilter() { logger.info("Loading ValidateCodeFilter..."); } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { String url = customYmlConfig.getLogins().getMobile().getUrl(); if (pathMatcher.match(url, request.getRequestURI())) {}} String deviceId = request.getHeader("deviceId"); if (StringUtils.isBlank(deviceId)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Não há deviceId no cabeçalho da solicitação"); } String codeParamName = customYmlConfig.getLogins().getMobile().getParameter().getCode(); String code = request.getParameter(codeParamName); if (StringUtils.isBlank(code)) { throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), "Não há código nos parâmetros da solicitação"); } String key = SystemConstant.DEFAULT_MOBILE_KEY_PIX + deviceId; SmsCodePO smsCodePo = (SmsCodePO) redisTemplate.opsForValue().get(key); if (smsCodePo.isExpried()){ throw new CustomException(HttpStatus.BAD_REQUEST.value(), "O código de verificação expirou"); } String smsCode = smsCodePo.getCode(); if (StringUtils.isBlank(smsCode)) { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Código de verificação inexistente"); } if (StringUtils.equals(code, smsCode)) {}} redisTemplate.delete(key); //Deixe-o ir filterChain.doFilter(request, response); } else { throw new CustomException(HttpStatus.BAD_REQUEST.value(), "O código de verificação é incorreto"); } }else { //Deixe-o ir filterChain.doFilter(request, response); } } }
Nota:doFilterInternal()
Verificação de filtro de código personalizado
2.2.2.2.Adicionar o filtro de verificação de código personalizado à cadeia de filtros do spring security
http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class)
Nota:Adicionar ao filtro de pré-processamento de autenticação
3.Teste de Efeito
Aqui está o endereço da fonte do código:https://gitee.com/CatalpaFlat/springSecurity.git (Download Local)
Resumo
Isso é tudo o que há no artigo. Espero que o conteúdo deste artigo tenha algum valor de referência para o seu aprendizado ou trabalho. Se tiver alguma dúvida, pode deixar um comentário para trocar ideias. Obrigado pelo apoio ao tutorial Yell.
Declaração: O conteúdo deste artigo é extraído da internet, pertence ao respectivo proprietário. O conteúdo é contribuído e carregado voluntariamente pelos usuários da internet. Este site não possui direitos de propriedade, não foi editado manualmente e não assume responsabilidade por eventuais responsabilidades legais. Se você encontrar conteúdo suspeito de violação de direitos autorais, por favor, envie um e-mail para: notice#oldtoolbag.com (ao enviar e-mail, substitua # por @ para denunciar, e forneça provas relevantes. Apenas quando confirmado, o site deletará o conteúdo suspeito de violação de direitos autorais.