Spring Security
- 스프링 기반의 애플리케이션의 보안(인증과 권한, 인가 등)을 담당하는 스프링 하위 프레임워크
- 스프링 시큐리티는 필터(Filter) 흐름에 따라 처리한다는 점
- 보안과 관련해서 체계적으로 많은 옵션을 제공해주기 때문에 일일이 보안 관련 로직을 작성하지 않아도 된다 굿!
- 참조 : https://mangkyu.tistory.com/76
[SpringBoot] Spring Security란?
대부분의 시스템에서는 회원의 관리를 하고 있고, 그에 따른 인증(Authentication)과 인가(Authorization)에 대한 처리를 해주어야 한다. Spring에서는 Spring Security라는 별도의 프레임워크에서 관련된 기능
mangkyu.tistory.com
1. dependency 추가 (Maven)
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 스프링 시큐리티에 대한 부분을 진행하기 위한 클래스 파일 생성
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
// 원하는 부분을 override 해서 사용하기
}
3. 오버라이드한 메서드들
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // csrf 일단 작동 안하도록 설정해놈
http.headers().frameOptions().sameOrigin();
http.authorizeRequests()
.antMatchers("/",
"/member/register",
"/member/email-auth",
"/member/find/password",
"/member/reset/password"
)
.permitAll(); // 로그인 없이 위 주소에 대해 권한 허용
http.authorizeRequests()
.antMatchers("/admin/**")
.hasAuthority("ROLE_ADMIN"); // 이 권한을 가져야 위 주소에 대해 권한 허용
http.formLogin()
.loginPage("/member/login") // 로그인 페이지 설정
.successHandler(userAuthenticationSuccessHandler) // 로그인 성공 시
.failureHandler(getFailureHandler()) // 로그인 실패 시
.permitAll();
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/member/logout")) // 로그아웃 경로
.logoutSuccessUrl("/") // 로그아웃이 성공되면 루트로 이동하고
.invalidateHttpSession(true); // 세션을 다 초기화 해준다
http.exceptionHandling()
.accessDeniedPage("/error/denied"); // 권한이 없는 사용자가 접근했을 시 이동할 경로
super.configure(http);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberService) // UserDetailService를 상속하여 loadUserByUsername 메서드를 구현해준 서비스
.passwordEncoder(getPasswordEncoder()); // 패스워드 인코더
super.configure(auth);
}
@Override
public void configure(WebSecurity web) throws Exception {
// resources 모든 접근을 허용하는 설정
// HttpSecurity 설정한 ADMIN권한을 가진 사용자만 resources 접근가능한 설정을 무시한다
web.ignoring().antMatchers("/favicon.ico", "/files/**"); // 무시하는 것들
super.configure(web);
}
4. successHandler, failureHandler
public class UserAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {
// 에러가 발생했을 때 호출되는 메서드
@Override
public void onAuthenticationFailure(
HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
String msg = "로그인에 실패하였습니다.";
if (exception instanceof InternalAuthenticationServiceException) {
msg = exception.getMessage();
}
setUseForward(true);
setDefaultFailureUrl("/member/login?error=true");
request.setAttribute("errorMessage", msg);
System.out.println("로그인에 실패하였습니다.");
super.onAuthenticationFailure(request, response, exception);
}
}
- failureHandler 만들기 예시
- 만든 SecurityConfiguration 클래스에 빈 주입하기
5. UserDetailService를 상속한 서비스 클래스에 loadUserByUsername 오버로드
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Member> optionalMember = memberRepository.findById(username);
if (!optionalMember.isPresent()) {
throw new UsernameNotFoundException("회원 정보가 존재하지 않습니다.");
}
Member member = optionalMember.get();
// failureHandler로 exception throw
if (Member.MEMBER_STATUS_REQ.equals(member.getUserStatus())) {
throw new MemberNotEmailAuthException("이메일 활성화 이후에 로그인을 해주세요.");
}
if (Member.MEMBER_STATUS_STOP.equals(member.getUserStatus())) {
throw new MemberStopUserException("정지된 회원입니다.");
}
if (Member.MEMBER_STATUS_WITHDRAW.equals(member.getUserStatus())) {
throw new MemberStopUserException("탈퇴한 회원입니다.");
}
// 권한 부여 1
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
// 권한 부여 2
if (member.isAdminYn()) { // 관리자 true면
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
} // ADMIN ROLE 추가
return new User(member.getUserId(), member.getPassword(), grantedAuthorities); // id, pw, 권한
}
ㅎ ㅎ
공부가 더 필요하겠어요 ~
+ 넘 잘 정리된 블로그 발견
[프로젝트 2] Spring Security를 활용한 인증, 인가 처리 로직 구현
문제점 이전 프로젝트에선 세션/쿠키 인증 방식으로 로그인 기능을 구현했고, 이를 위한 로직을 직접 코드로 작성했었습니다. 그로 인해 제가 직접 구현된 로직 내에서 발생할 수 있는 에러의
velog.io
'Spring' 카테고리의 다른 글
[Spring] Swagger로 API 문서 자동화하기 (0) | 2023.01.04 |
---|---|
[Spring] MyBatis (0) | 2022.12.19 |
[Spring] JavaMailSender 이메일 전송하기 (0) | 2022.12.09 |
[Spring] JpaAuditing (0) | 2022.10.30 |
[Spring] JUnit과 Mokito/단위 테스트 코드 (0) | 2022.10.25 |