UserDetailsService 인터페이스는 DB에서 유저 정보를 가져오는 역할을 한다. 해당 인터페이스의 메소드에서 DB의 유저 정보를 가져와서 AuthenticationProvider 인터페이스로 유저 정보를 리턴
- 인증 및 권한부여 절차
UserDetails
Spring Security에서 사용자의 정보를 담는 인터페이스는 UserDetails 인터페이스이다.
우리가 이 인터페이스를 구현하게 되면 Spring Security에서 구현한 클래스를 사용자 정보로 인식하고 인증 작업을 한다.
쉽게 말하면 UserDetails 인터페이스는 VO 역할을 한다고 보면 된다.
@SuppressWarnings("serial")
@Data
@Component
public class MemberDTO implements UserDetails {
private String member_email;
private String member_pwd;
private String member_name;
private String member_nickname;
private String member_profile;
private int member_flag;
private int member_seq;
private Date logtime;
private String memberAuthKey; // 이메일 인증키
private int memberAuthStatus; // 이메일 인증상태
private String memberAuthority; // 멤버 권한
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auth = new ArrayList<GrantedAuthority>();
if (this.member_nickname.equals("admin")) {
auth.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
} else {
auth.add(new SimpleGrantedAuthority("ROLE_USER"));
}
return auth;
}
@Override
public String getPassword() {
return "{noop}" + member_pwd;
}
@Override
public String getUsername() {
return member_email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
UserDetails 인터페이스를 구현하게 되면 오버라이드되는 메소드들에 대해 간략하게 설명!
+ 오버라이드되는 메소드들만 Spring Security에서 알아서 이용하기 때문에 따로 클래스를 만들지 않고 멤버변수를 추가해서 같이 사용해도 무방하다. 만든 멤버변 수들은 getter, setter를 만들어서 사용하면 된다
매소드명 | 리턴타입 | 설명 |
getAuthorities() |
Collection<? extends GrantedAuthority> |
계정이 가지고 있는 권한 목록 리턴 |
getPassword() | String | 계정의 비밀번호 리턴 |
getUsername() | String | 계정의 이름 리턴 |
isAccountNonExpired() | boolean | 계정이 만료되지 않았는지 리턴(true:만료x) |
isAccountNonLocked() | boolean | 계정이 잠겨있지 않았는지 리턴(true : 잠김x) |
isCredentialNonExpired() | boolean | 비밀번호가 만료되지 않았는지 리턴(true: 만료x) |
isEnabled() | boolean | 계정이 활성화(사용가능)인지 리턴(true:활성화) |
CustomUserDetailService.java
//유저정보를 DB를 가지고 오는 클래스
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private MemberDAO memberDAO;
@Override
public UserDetails loadUserByUsername(String member_email) throws UsernameNotFoundException {
MemberDTO member = memberDAO.getMemberByEmail(member_email);
if (member == null) {
throw new UsernameNotFoundException(member_email);
}
return member;
}
}
MemberDAOMybatis
// 이메일로 회원 정보 가지고 오기.
@Override
public MemberDTO getMemberByEmail(String member_email) {
return sqlSession.selectOne("memberSQL.getMemberByEmail", member_email);
}
MemberDAOMapper.xml
<!-- 이메일로 회원정보 가지고 오기 -->
<select id="getMemberByEmail" parameterType="String" resultType="member">
select * from mentors_member where member_email = #{member_email}
</select>
security.xml
<authentication-manager>
<authentication-provider ref="customMemberAuthProvider"/>
//유저 정보를 가져오는 클래스를 설정하는 곳
<authentication-provider user-service-ref="customMemberService"/>
</authentication-manager>
<beans:bean id="customMemberService" class="member.service.CustomUserDetailsService"/>
AuthenticationProvider
AuthertucationProvider 인터페이스는 화면에서 입력한 로그인 정보와 DB에서 가져온 사용자의 정보를 비교해주는 인터페이스!!
- authenticate() : 화면에서 사용자가 입력한 로그인 정보를 담고 있는 Authentication 객체를 가지고 있다.
- supports(class<?> authentication ) : AuthenticationProvider 인터페이스가 지정된 Authentication 객체를 지원하는 경우에 true를 리턴한다.
+ DB에서 사용자의 정보를 가져오는 건 위에서 구현했던 UserDetailsService 인터페이스에서 loadUserByUsername() 메서드를 통해 구현했었다
public class CustomAuthenticationProvider implements AuthenticationProvider {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String member_email = (String) authentication.getPrincipal();
String member_pwd = (String) authentication.getCredentials();
MemberDTO member = (MemberDTO) customUserDetailsService.loadUserByUsername(member_email);
//bcrypt의 비밀번호 체크 메소드
if (!passwordEncoder.matches(member_pwd, member.getMember_pwd())) {
throw new BadCredentialsException(member_email);
}
if (member.getMemberAuthStatus() == 0) {
throw new DisabledException(member_email);
}
//권한 부여: memberDTO의 getAuthorities() 메소드에서 담당.
List<GrantedAuthority> roles = (List<GrantedAuthority>) member.getAuthorities();
// 스프링 시큐리티 내부 클래스로 인증 토큰 생성
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(member_email, member_pwd, roles);
return result;
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
security.xml
<authentication-manager>
<authentication-provider ref="customMemberAuthProvider"/>
<authentication-provider user-service-ref="customMemberService"/>
</authentication-manager>
<beans:bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
<beans:bean id="customMemberService" class="member.service.CustomUserDetailsService"/>
<beans:bean id="customMemberAuthProvider" class="member.service.CustomAuthenticationProvider"/>
'Spring Framework > project' 카테고리의 다른 글
CSRF 는 무엇인가? (0) | 2020.02.12 |
---|---|
Spring 실시간 알림(webSocket) (15) | 2020.01.26 |
Spring Security - LoginFailureHandler (0) | 2020.01.06 |
Spring Security - LoginSucessHandler (0) | 2020.01.06 |
spring security 환경설정 (0) | 2020.01.06 |