English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية

spring security로 사용자 인증 및 로그인 전체 과정 기록

正文

spring security使用分類:

1如何使用spring security,相信百度過的都知道,總共有四種用法,從簡到深為:

2、不用數據庫,全部數據寫在配置文件,這也是官方文檔裡面的demo;

3、使用數據庫,根據spring security默認實現代碼設計數據庫,也就是說數據庫已經固定了,這種方法不靈活,而且那個數據庫設計得很簡陋,實用性差;

4、spring security和Acegi不同,它不能修改默認filter了,但支持插入filter,所以根據這個,我們可以插入自己的filter來靈活使用;

、暴力手段,修改源碼,前面說的修改默認filter只是修改配置文件以替換filter而已,這種是直接改了里面的源碼,但是這種不符合OO設計原則,而且不實際,不可用。

1本文主要介紹了關於spring security自定義認證登錄的有關內容,分享出來供大家參考學習,下面話不多說了,來一起看看詳細的介紹吧。

1.1.概要

.簡介

1.2.spring security 自定義認證流程

1)認證過程

生成未認證的AuthenticationToken                 

 ↑(獲取信息)  (根據AuthenticationToken分配provider)     
 AuthenticationFilter -> AuthenticationManager -> AuthenticationProvider
        ↓(認證)
       UserDetails(一般查詢數據庫獲取)
        ↓(通過)
        生成認證成功的AuthenticationToken
         ↓(存放)
        SecurityContextHolder

2)將AuthenticationFilter加入至security過濾鏈(資源服務器中配置),如:

http.addFilterBefore(AuthenticationFilter, AbstractPreAuthenticatedProcessingFilter.class)

또는:}

http.addFilterAfter(AuthenticationFilter, UsernamePasswordAuthenticationFilter.class)

2.휴대폰 번호 문자 인증 예제로

2.1.개발 환경

  • SpringBoot
  • Spring security
  • Redis

2.2.핵심 코드 분석

2.2.1.사용자 정의 로그인 인증 프로세스

2.2.1.1.사용자 정의 인증 로그인 토큰

/**
 * 휴대폰 로그인 토큰
 *
 * @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(
   "이 토큰을 신뢰할 수 없음 - GrantedAuthority 목록을 받는 생성자를 사용하십시오);
 }
 super.setAuthenticated(false);
 }
 @Override
 public Object getCredentials() {
 return null;
 }
 @Override
 public Object getPrincipal() {
 return this.principal;
 }
 @Override
 public void eraseCredentials() {
 super.eraseCredentials();
 }
}

주의:

setAuthenticated():인증 여부�断정

  • 필터에서는 인증되지 않은 AuthenticationToken을 생성하며, 이때 사용자 정의 토큰의 setAuthenticated()를 호출하며 이를 false로 설정합니다 -> 인증되지 않음
  • 제공자에서는 인증된 AuthenticationToken을 생성하며, 이때 부모 클래스의 setAuthenticated()를 호출하며 이를 true로 설정합니다 -> 인증됨

2.2.1.1.사용자 정의 인증 로그인 필터

/**
 * 휴대폰 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 로딩 중... ");
 }
 @Override
 public Authentication attemptAuthentication(HttpServletRequest request,      HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
 if (postOnly && !request.getMethod().equals(HttpMethod.POST.name())) {
  throw new AuthenticationServiceException("인증 메서드가 지원되지 않습니다: " + request.getMethod());
 }
 //모바일을 가져옵니다
 String mobile = obtainMobile(request);
 //tokken을 조립합니다
 MobileLoginAuthenticationToken authRequest = new MobileLoginAuthenticationToken(mobile);
 // 하위 클래스에 "details" 속성을 설정할 수 있도록 허용합니다
 setDetails(request, authRequest);
 return this.getAuthenticationManager().authenticate(authRequest);
 }
 /**
 * 인증 정보의 세부 사항을 설정합니다
 */
 private void setDetails(HttpServletRequest request, MobileLoginAuthenticationToken authRequest) {
 authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
 }
 /**
 * 휴대폰 번호 가져오기
 */
 private String obtainMobile(HttpServletRequest request) {
 return request.getParameter(mobileParameterName);
 }
 public void setPostOnly(boolean postOnly) {
 this.postOnly = postOnly;
 }
}

주의:attemptAuthentication() 메서드:

  • 지정된 URL, httpMethod 필터링
  • 필요한 요청 파라미터 데이터를 포장하여 미인증된 AuthenticationToken 생성
  • AuthenticationManager에 인증 전달

2.2.1.1.사용자 정의 인증 로그인 제공자

/**
 * 휴대폰 문자 메시지 로그인 인증 제공자
 *
 * @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 loading ...");
 }
 /**
 * 인증
 */
 @Override
 public Authentication authenticate(Authentication authentication) throws AuthenticationException {
 //필터가 감싸는 token 정보를 가져온다
 MobileLoginAuthenticationToken authenticationToken = (MobileLoginAuthenticationToken) authentication;
 //사용자 정보 가져오기(데이터베이스 인증)
 UserDetails userDetails = customUserDetailsService.loadUserByUsername((String) authenticationToken.getPrincipal());
 //통과하지 않음
 if (userDetails == null) {
  throw new InternalAuthenticationServiceException("사용자 정보를 가져올 수 없음");
 }
 //통과
 MobileLoginAuthenticationToken authenticationResult = new MobileLoginAuthenticationToken(userDetails, userDetails.getAuthorities());
 authenticationResult.setDetails(authenticationToken.getDetails());
 return authenticationResult;
 }
 /**
 * token 타입에 따라 사용할 Provider를 판단
 */
 @Override
 public boolean supports(Class<?> authentication) {
 return MobileLoginAuthenticationToken.class.isAssignableFrom(authentication);
 }
}

주의:authenticate() 메서드

  • 필터가 감싸는 token 정보를 가져온다
  • UserDetailsService를 호출하여 사용자 정보를 가져온다(데이터베이스 인증)-> 통과 여부 판단
  • 통과하면 새로운 AuthenticationToken을 감싸고 반환

2.2.1.1.사용자 정의 인증 로그인 인증 구성

@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 모바일로그인인증필터 = new MobileLoginAuthenticationFilter(StringUtils.isBlank(url) ? defaultMobileLoginUrl : url,
  StringUtils.isBlank(parameter) ? defaultMobileLoginUrl : parameter, StringUtils.isBlank(httpMethod) ? defaultMobileLoginHttpMethod : httpMethod); 모바일로그인인증필터.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class)); 모바일로그인인증필터.setAuthenticationSuccessHandler(customAuthenticationSuccessHandler); 모바일로그인인증필터.setAuthenticationFailureHandler(customAuthenticationFailureHandler);
 MobileLoginAuthenticationProvider 모바일로그인인증공급자 = new MobileLoginAuthenticationProvider(); 모바일로그인인증공급자.setCustomUserDetailsService(customUserDetailsService);
 http.authenticationProvider(모바일로그인인증공급자)
  .addFilterAfter(모바일로그인인증필터, UsernamePasswordAuthenticationFilter.class);
 }
}

주의:configure() 메서드

AuthenticationFilter와 AuthenticationProvider를 인스턴스화합니다.

AuthenticationFilter와 AuthenticationProvider를 Spring Security에 추가합니다.

2.2.2. Redis 기반 사용자 정의 인증 코드 검증

2.2.2.1. Redis 기반 사용자 정의 인증 코드 필터

/**
 * 인증 코드 필터
 *
 * @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;
 /**
  * 페이지 요청 URL과 설정된 URL이 일치하는지 확인하는 도구 클래스
  */
 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(), \
   }
   String codeParamName = customYmlConfig.getLogins().getMobile().getParameter().getCode();
   String code = request.getParameter(codeParamName);
   if (StringUtils.isBlank(code)) {
    throw new CustomException(HttpStatus.NOT_ACCEPTABLE.value(), \
   }
   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(), \
   }
   String smsCode = smsCodePo.getCode();
   if (StringUtils.isBlank(smsCode)) {
    throw new CustomException(HttpStatus.BAD_REQUEST.value(), \
   }
   if (StringUtils.equals(code, smsCode)) {
    redisTemplate.delete(key);
    //let it go
    filterChain.doFilter(request, response);
   }
    throw new CustomException(HttpStatus.BAD_REQUEST.value(), "Validation code is incorrect");
   }
  }
   //let it go
   filterChain.doFilter(request, response);
  }
 }
}

주의:doFilterInternal()

사용자 정의��인 코드 필터 검증

2.2.2.2.사용자 정의��인 코드 필터를 스프링 시큐리티 필터 체인에 추가

http.addFilterBefore(validateCodeFilter, AbstractPreAuthenticatedProcessingFilter.class)

주의:인증 предобработка фильтр에 추가하기 전에

3.테스트 효과

마지막으로 소스 코드 주소를 추가합니다:https://gitee.com/CatalpaFlat/springSecurity.git  (로컬 다운로드

정리

이것이 이 문서의 모든 내용입니다. 이 문서의 내용이 여러분의 학습이나 업무에 도움이 되길 바랍니다. 문제가 있으면 댓글을 달아 주시고, 감사합니다.呐喊 가이드에 대한 여러분의 지지에 감사합니다.

선언: 본 문서의 내용은 인터넷에서 가져왔으며, 저작권은 원작자에게 있으며, 인터넷 사용자가 자발적으로 기여하고 업로드한 내용으로, 본 사이트는 소유권을 가지지 않으며, 인공 편집을 거치지 않았으며, 관련 법적 책임도 부담하지 않습니다. 저작권 문제가 있는 내용을 발견하면 notice#w로 이메일을 보내 주시기 바랍니다.3codebox.com에 (이메일을 보내는 경우, #을 @으로 변경하십시오) 신고하시고 관련 증거를 제공하시면, 해당 내용이 사실로 확인되면 즉시 해당 내용을 삭제하겠습니다.

좋아할 만한 항목