SpringSceurity 문자 인증 코드 로그 인 실현
문자 인증 코드 의 로그 인 체 제 를 이해 하기 전에 저 희 는 먼저 사용자 계 정 비밀번호 로그 인 체제 가 어떻게 되 는 지 알 아야 합 니 다.Spring Security 가 사용자 이름과 비밀번호 로그 인 방식 을 어떻게 검증 하 는 지 간략하게 분석 해 보 겠 습 니 다.
분석 이 끝 난 뒤 문자 로그 인 검증 방식 을 스프링 시 큐 리 티 에 통합 하 는 방법 을 함께 고민해 보 자.
1.계 정 비밀번호 로그 인 절차
일반 계 정 비밀번호 로그 인 에는 도형 인증 코드 와 내 기능 이 첨부 되 어 있 는데 그 대략적인 절 차 는 이렇다.
1.사용자 가 사용자 이름,계 정,이미지 인증 코드 를 입력 한 후에 클릭 하여 로그 인 합 니 다.그러면 spring Sceurity 에 대해 서 는 먼저 문자 인증 코드 Filter 에 들 어 갑 니 다.설정 할 때 설정 하기 때 문 입 니 다.
UsernamePassword AuthenticationFilter 에 앞서 현재 인증 코드 의 정 보 를 session 에 존재 하 는 이미지 인증 코드 와 검증 합 니 다.
2.문자 인증 코드 통과 후 UsernamePassword AuthenticationFilter 에 들 어가 입력 한 사용자 이름과 비밀번호 정보 에 따라 일시 적 으로 인증 권 이 없 는
UsernamePassword AuthenticationToken,그리고 UsernamePassword AuthenticationToken 을 AuthenticationManager 에 맡 깁 니 다.
3.AuthenticationManager 자체 가 검증 처 리 를 하지 않 습 니 다.그 는 for-each 를 통 해 현재 로그 인 방식 에 맞 는 AuthenticationProvider 를 찾 아 검증 처 리 를 합 니 다.
사용자 이름 비밀번호 로그 인 방식 에 대해 이 Provider 가 바로 Dao AuthenticationProvider 입 니 다.
4.이 Provider 에서 일련의 검증 처 리 를 하고 검증 이 통과 되면 인증 권 을 추가 한 UsernamePassword AuthenticationToken 을 재 구성 하고 이 를
token 은 UsernamePassword AuthenticationFilter 로 전 달 됩 니 다.
5.이 Filter 의 부모 클래스 Abstract Authentication Processing Filter 에 서 는 이전 검증 결과 에 따라 successHandler 또는 failure Handler 로 이동 합 니 다.
흐름 도
2.문자 인증 코드 로그 인 절차
문자 로그 인 방식 이 Spring Security 에 통합 되 지 않 았 기 때문에 문자 로그 인 논 리 를 개발 하여 Spring Security 에 통합 시 켜 야 하 는 경우 가 많 습 니 다.그러면 여기 서 우 리 는 계 정 을 모방 합 니 다.
비밀번호 로그 인하 여 문자 인증 코드 로그 인 을 실현 합 니 다.
1.사용자 이름 비밀번호 로그 인 에 UsernamePassword AuthenticationFilter 가 있 습 니 다.우 리 는 Sms AuthenticationFilter 를 만 들 고 코드 를 붙 여 고 칩 니 다.
2.사용자 이름 비밀번호 로그 인 은 UsernamePassword AuthenticationToken 이 필요 합 니 다.우 리 는 Sms AuthenticationToken 을 만 들 고 코드 를 붙 여 고 쳐 야 합 니 다.
3.사용자 이름 비밀번호 로그 인 은 Dao AuthenticationProvider 가 필요 합 니 다.이 를 모방 하 는 것 도 implenments AuthenticationProvider 입 니 다.Sms AuthenticationProvider 라 고 합 니 다.
이 그림 은 인터넷 에서 찾 은 것 이 므 로,자신 은 그 리 려 고 하지 않 는 다.
우리 스스로 위의 세 가지 유형 을 만 든 후에 실현 하고 자 하 는 효 과 는 위의 그림 과 같다.우리 가 문자 인증 코드 로 로그 인 할 때:
1.먼저 Sms AuthenticationFilter 를 거 쳐 인증 권 이 없 는 Sms AuthenticationToken 을 구성 한 다음 AuthenticationManager 에 맡 깁 니 다.
2.AuthenticationManager 는 for-each 를 통 해 적당 한 provider 를 선택 하여 처리 합 니 다.물론 이 provider 가 Sms AuthenticationProvider 라면 좋 겠 습 니 다.
3.검증 이 통과 되면 인증 권 이 있 는 Sms AuthenticationToken 을 재 구성 하고 Sms AuthenticationFilter 에 되 돌려 줍 니 다.
filter 는 이전 검증 결과 에 따라 성공 하거나 실패 한 처리 논리 로 넘 어 갑 니 다.
코드 구현
1、SmsAuthenticationToken
먼저 Sms AuthenticationToken 을 작 성 했 습 니 다.여 기 는 UsernamePassword AuthenticationToken 소스 코드 를 직접 참고 하여 직접 붙 여 고 칩 니 다.
principal 은 원래 사용자 이름 을 대표 하 는데 여 기 는 보류 하고 핸드폰 번호 만 대표 합 니 다.credentials 원래 코드 비밀번호,문자 로그 인 이 사용 되 지 않 아 바로 삭제 합 니 다.
Sms Code Authentication Token()두 가지 구조 방법 중 하 나 는 구조 가 감 권 이 없 는 것 이 고 하 나 는 구조 가 감 권 이 있 는 것 이다.
나머지 몇 가지 방법 으로 무용 속성 을 제거 하면 됩 니 다.
public class SmsCodeAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
/**
* UsernamePasswordAuthenticationToken ,
*
*/
private final Object principal;
/**
* SmsCodeAuthenticationToken
*/
public SmsCodeAuthenticationToken(Object principal) {
super(null);
this.principal = principal;
setAuthenticated(false);
}
/**
* SmsCodeAuthenticationToken
*/
public SmsCodeAuthenticationToken(Object principal, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
// must use super, as we override
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return null;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException(
"Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
}
super.setAuthenticated(false);
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
}
}
2、SmsAuthenticationFilter그리고 Sms AuthenticationFilter 를 작성 하고 UsernamePassword AuthenticationFilter 의 원본 코드 를 참고 하여 직접 붙 여 고치 세 요.
원래 정적 필드 는 username 과 password 가 있 습 니 다.모두 제거 하고 우리 의 핸드폰 번호 필드 로 바 꿉 니 다.Smscode AuthenticationFilter()에서 이 filter 의 차단 Url 을 지 정 했 습 니 다.저 는
post /sms/login
으로 지 정 했 습 니 다.남 은 방법 은 무효 한 것 을 삭제 하고 고치 면 된다.
public class SmsCodeAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
/**
* form name
*/
public static final String SPRING_SECURITY_FORM_MOBILE_KEY = "mobile";
private String mobileParameter = "mobile";
/**
* POST
*/
private boolean postOnly = true;
public SmsCodeAuthenticationFilter() {
// /sms/login post
super(new AntPathRequestMatcher("/sms/login", "POST"));
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String mobile = obtainMobile(request);
if (mobile == null) {
mobile = "";
}
mobile = mobile.trim();
SmsCodeAuthenticationToken authRequest = new SmsCodeAuthenticationToken(mobile);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainMobile(HttpServletRequest request) {
return request.getParameter(mobileParameter);
}
protected void setDetails(HttpServletRequest request, SmsCodeAuthenticationToken authRequest) {
authRequest.setDetails(authenticationDetailsSource.buildDetails(request));
}
public String getMobileParameter() {
return mobileParameter;
}
public void setMobileParameter(String mobileParameter) {
Assert.hasText(mobileParameter, "Mobile parameter must not be empty or null");
this.mobileParameter = mobileParameter;
}
public void setPostOnly(boolean postOnly) {
this.postOnly = postOnly;
}
}
3、SmsAuthenticationProvider이 방법 은 비교적 중요 하 다.이 방법 은 먼저 문자 인증 코드 를 사용 하여 로그 인 할 때 AuthenticationManager 에 의 해 선택 되 고 그 다음 에 이 클래스 에서 검증 논 리 를 처리 해 야 한다.
AuthenticationProvider 인 터 페 이 스 를 실현 하고 authenticate()와 supports()방법 을 실현 합 니 다.
public class SmsCodeAuthenticationProvider implements AuthenticationProvider {
private UserDetailsService userDetailsService;
/**
* session
*/
private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy();
String SESSION_KEY_PREFIX = "SESSION_KEY_FOR_CODE_SMS";
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
SmsCodeAuthenticationToken authenticationToken = (SmsCodeAuthenticationToken) authentication;
String mobile = (String) authenticationToken.getPrincipal();
checkSmsCode(mobile);
UserDetails userDetails = userDetailsService.loadUserByUsername(mobile);
// , new authenticationResult
SmsCodeAuthenticationToken authenticationResult = new SmsCodeAuthenticationToken(userDetails, userDetails.getAuthorities());
authenticationResult.setDetails(authenticationToken.getDetails());
return authenticationResult;
}
private void checkSmsCode(String mobile) {
HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
// session
SmsCode smsCodeInSession = (SmsCode) sessionStrategy.getAttribute(new ServletWebRequest(request), SESSION_KEY_PREFIX);
String inputCode = request.getParameter("smsCode");
if(smsCodeInSession == null) {
throw new BadCredentialsException(" ");
}
String mobileSsion = smsCodeInSession.getMobile();
if(!Objects.equals(mobile,mobileSsion)) {
throw new BadCredentialsException(" ");
}
String codeSsion = smsCodeInSession.getCode();
if(!Objects.equals(codeSsion,inputCode)) {
throw new BadCredentialsException(" ");
}
}
@Override
public boolean supports(Class<?> authentication) {
// authentication SmsCodeAuthenticationToken
return SmsCodeAuthenticationToken.class.isAssignableFrom(authentication);
}
public UserDetailsService getUserDetailsService() {
return userDetailsService;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
}
4、SmsCodeAuthenticationSecurityConfig차단 기 를 사용자 정의 한 이상 설정 에서 변경 할 수 있 습 니 다.
@Component
public class SmsCodeAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
@Autowired
private SmsUserService smsUserService;
@Autowired
private AuthenctiationSuccessHandler authenctiationSuccessHandler;
@Autowired
private AuthenctiationFailHandler authenctiationFailHandler;
@Override
public void configure(HttpSecurity http) {
SmsCodeAuthenticationFilter smsCodeAuthenticationFilter = new SmsCodeAuthenticationFilter();
smsCodeAuthenticationFilter.setAuthenticationManager(http.getSharedObject(AuthenticationManager.class));
smsCodeAuthenticationFilter.setAuthenticationSuccessHandler(authenctiationSuccessHandler);
smsCodeAuthenticationFilter.setAuthenticationFailureHandler(authenctiationFailHandler);
SmsCodeAuthenticationProvider smsCodeAuthenticationProvider = new SmsCodeAuthenticationProvider();
//
smsCodeAuthenticationProvider.setUserDetailsService(smsUserService);
http.authenticationProvider(smsCodeAuthenticationProvider)
.addFilterAfter(smsCodeAuthenticationFilter, UsernamePasswordAuthenticationFilter.class);
}
}
5、SmsUserService사용자 이름,비밀번호 로그 인 은 최종 적 으로 사용자 이름 을 통 해 사용자 정 보 를 조회 하 는 것 이 고,모 바 일 인증 코드 로그 인 은 모 바 일 로그 인 을 통 해 이 루어 지기 때문에 자신 이 SmsUserService 를 하나 더 실현 해 야 합 니 다.
@Service
@Slf4j
public class SmsUserService implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Autowired
private RolesUserMapper rolesUserMapper;
@Autowired
private RolesMapper rolesMapper;
/**
*
*/
@Override
public UserDetails loadUserByUsername(String mobile) throws UsernameNotFoundException {
log.info(" , = {}",mobile);
//TODO sql, user , mobile ,
//TODO ( )
User user = userMapper.findOneByUsername(" ");
if (user == null) {
throw new UsernameNotFoundException(" ");
}
//
List<RolesUser> userList = rolesUserMapper.findAllByUid(user.getId());
if (CollectionUtils.isEmpty(userList)) {
return user;
}
// ID
List<Integer> ridList = userList.stream().map(RolesUser::getRid).collect(Collectors.toList());
List<Roles> rolesList = rolesMapper.findByIdIn(ridList);
//
user.setRoles(rolesList);
return user;
}
}
6.총화여기까지 오 면 생각 이 뚜렷 해 집 니 다.제 가 정리 하 겠 습 니 다.
1.먼저 인증 을 받 을 때 부터 현재 인증 코드 정 보 를 session 에 저 장 했 습 니 다.이 정 보 는 인증 코드 와 핸드폰 번 호 를 포함 합 니 다.
2.사용자 가 인증 로그 인 을 입력 합 니 다.여 기 는 Sms AuthenticationFilter 에 직접 쓰 여 있 습 니 다.먼저 인증 코드,핸드폰 번호 가 정확 한 지 확인 한 다음 에 사용자 정 보 를 조회 합 니 다.저희 도 아 이 디 비밀번호 로 뜯 어서 로그 인 할 수 있어 요.
필 터 는 인증 코드 와 핸드폰 번호 가 정확 한 지 검증 하고 인증 코드 를 걸 어서 필 터 를 로그 인 합 니 다.
3.Sms Authentication Filter 프로 세 스에 서도 키 와 관련 된 단 계 는 사용자 이름 비밀번호 로그 인 은 사용자 정의 UserService 를 통 해 UserDetails 서 비 스 를 실현 한 후 사용자 이름 을 통 해 사용자 이름 정 보 를 조회 하 는 것 입 니 다.
휴대 전화 번 호 를 통 해 사용자 정 보 를 조회 하기 때문에 SmsUserService 를 사용자 정의 하여 UserDetails Service 를 실현 한 후.
테스트
1.인증번호 가 져 오기
인증 코드 를 받 은 휴대 전화 번 호 는 15612345678 이다.제3자 문자 SDK 를 받 지 않 고 백 스테이지 에서 만 출력 했 기 때문이다.
핸드폰 번호:15612345678 의 사용자 에 게 인증 번 호 를 보 냅 니 다:254792
2.로그 인
1)인증번호 입력 이 정확 하지 않 음
로그 인 에 실 패 했 습 니 다.마찬가지 로 핸드폰 번호 입력 이 틀 리 면 로그 인 에 실 패 했 습 니 다.
2)로그 인 성공
휴대 전화 번호 와 문자 인증 번호 가 모두 정확 한 상황 에서 로그 인 에 성공 했다.
레 퍼 런 스
1.Spring Security 기술 창고 개발 기업 급 인증 및 권한 수여(JoJo)
2、 SpringSceurity 문자 인증 코드 기능 구현 예시 코드
SpringSceurity 의 문자 인증 코드 로그 인 에 관 한 이 글 은 여기까지 소개 되 었 습 니 다.SpringSceurity 문자 인증 코드 로그 인 내용 에 대해 서 는 예전 의 글 을 검색 하거나 아래 의 관련 글 을 계속 읽 어 주시 기 바 랍 니 다.앞으로 도 많은 응원 부 탁 드 리 겠 습 니 다!
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
[MeU] Hashtag 기능 개발➡️ 기존 Tag 테이블에 존재하지 않는 해시태그라면 Tag , tagPostMapping 테이블에 모두 추가 ➡️ 기존에 존재하는 해시태그라면, tagPostMapping 테이블에만 추가 이후에 개발할 태그 기반 ...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.