SpringBoot - Spring Security
config - WebSecurityConfig.java
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
// 패스워드 인코더
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http
.csrf().disable() // jwt토큰 방식을 쓰기에 필요한 설정
.authorizeRequests() // HttpServletRequest를 사용하는 요청들에 대한 접근제한을 설정
.antMatchers("/joinMember","loginMember").permitAll() // 해당요청은 인증없이 접근허용
.anyRequest().authenticated() // 나머지 요청들은 인증받아야함
// 다른 페이지로 가면 로그인페이지로 자동 리다이렉트
.and()
.formLogin()
.loginPage("/login")
.usernameParameter("m_id")
.passwordParameter("m_pw")
.loginProcessingUrl("/loginMember") // /loginMember 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행
config - auth - PrincipalDetails
- 시큐리티가 loginProcessingUrl인 /loginMember 주소 요청이 오면 낚아채서 로그인 진행 진행
- 로그인을 진행이 완료가 되면 시큐리티 session을 만들어준다. ( Security ContextHolder )
- 오브젝트 => Authentication 타입 객체
- Authentication 안에 user 정보가 있어야 함
- user 오브젝트타입 => UserDetails 타입 객체
- Security Session => Authentication => UserDetails(PrincipalDetails_
@Data
public class PrincipalDetails implements UserDetails,OAuth2User {
private memberVO mem;
private Map<String,Object> attributes;
// 일반로그인
public PrincipalDetails(memberVO mem) {
this.mem = mem;
}
// OAuth로그인
public PrincipalDetails(memberVO mem, Map<String, Object> attributes) {
this.mem = mem;
this.attributes = attributes;
}
// 해당 User의 권한을 리턴하는 곳곳
@Override
public Collection<? extends GrantedAuthority> getAuthorities(){
Collection<GrantedAuthority> collet = new ArrayList<>();
collet.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return mem.getM_role();
}
});
return collet;
};
@Override
public String getPassword(){
return mem.getM_pw();
};
@Override
public String getUsername(){
return mem.getM_id();
};
@Override
public boolean isAccountNonExpired(){
return true;
};
@Override
public boolean isAccountNonLocked(){
return true;
};
@Override
public boolean isCredentialsNonExpired(){
return true;
};
@Override
public boolean isEnabled(){
// 사이트에서 1년동안 회원이 로그인을 안하면 휴면계정
// mem.getLoginDate()
// 현재 시간 - 로그인시간 => 1년을 초과하면 return false;
return true;
};
@Override
public Map<String, Object> getAttributes() {
return attributes;
}
@Override
public String getName() {
return null;
}
}
config - auth - PrincipalDetailsService
- 시큐리티 설정에서 loginProcessingUrl("/login")
- /login 요청이 오면 자동으로 UserDetailService타입으로 IoC되어있는 loadUserByUsername함수가 실행
- 시큐리티 session => Authentication => UserDetails => Authentication(내부 UserDetails) => 시큐리티 session
@Service
public class PrincipalDetailsService implements UserDetailsService {
@Autowired
private memberMapper memberMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(11111);
memberVO user = memberMapper.selectId(username);
if(user != null){
System.out.println(11111);
return new PrincipalDetails(user);
}
return null;
}
}
참고자료
: https://blog.naver.com/getinthere/222064999924
https://www.youtube.com/watch?v=6n4k8Van_HI&list=PL93mKxaRDidERCyMaobSLkvSPzYtIk0Ah&index=4
Springboot + Spring Security + React를 시도하였으나 .loginProcessingUrl를 이용한 방법은 SpringBoot의 폼태그가 있는 클라이언트 페이지와 Action값을 따라가는 것 같음. React를 연동해보았으나 계속 PrincipalDetailsService를 찾지 못함.
-> 예제를 찾아봐도 거의 다 Spring Security + React는 JWT 방법을 씀, 그래서 JWT 방법으로 변경
2022-06-09
.loginProcessingUrl를 이용한 해결방법
- react에서 spring으로 데이터를 보낼때 데이터 형식을 Content-Type: application/json 형태로 보냄.
- form 태그의 형식은 Content-Type: application/x-www-form-urlencoded 사용함
- 적용은 안해봤지만 아마 될 것으로 예상...