Spring/Spring Security
[Security] 간단한 구현을 위한 정리
doriver
2022. 11. 15. 21:54
Security를 이용해 로그인/로그아웃, 권한설정 등을 처리
설정은 WebSecurityConfigurerAdapter라는 클래스를 상속받은 클래스에서 메서드를 오버라이딩하여 조정
@Configuration
@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private MemberService memberService;
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder(); // BCryptPasswordEncoder는 Spring Security에서 제공하는 비밀번호 암호화 객체
} // 비밀번호를 암호화할 수 있도록 Bean으로 등록
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring(). ~ ~ ; // Spring Security가 무시할 수 있도록 설정
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests(). ~ ~ // 페이지 권한 설정 , HttpServletRequest에 따라 접근을 제한
.and().formLogin(). ~ ~ // 로그인 설정 , form 기반으로 인증을 하도록 함( 로그인 정보는 기본적으로 HttpSession을 이용 )
.and().logout(). ~ ~ // 로그아웃 설정
.and().exceptionHandling(). ~ ~ ; // 예외처리 핸들링
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberService).passwordEncoder(passwordEncoder()); // 로그인 처리(인증)
}
}
위 코드에서 일부를 아래와 같이 간략화 해서 보기 편하게 해봄
void configure(WebSecurity web) { web. ~ ~ ; }
// WebSecurity는 FilterChainProxy를 생성하는 필터
void configure(HttpSecurity http) { http. ~ ~ ; }
// HttpSecurity를 통해 HTTP 요청에 대한 웹 기반 보안을 구성
void configure(AuthenticationManagerBuilder auth) { auth. ~ ~ ; }
// Spring Security에서 모든 인증은 AuthenticationManager를 통해 이루어진다.
로그인 처리(인증)을 위해 클래스MemberService에서
인터페이스UserDetailsService를 implements하여, 메서드loadUserByUsername()를 구현
@Service
@AllArgsConstructor
public class MemberService implements UserDetailsService {
private MemberRepository memberRepository;
@Transactional
public Long joinUser(MemberDto memberDto) { // 회원가입을 처리하는 메서드
// 비밀번호 암호화 하여 저장
~ ~
~ ~
return ~ ;
}
@Override // 상세 정보를 조회하는 메서드
public UserDetails loadUserByUsername(String userEmail) throws UsernameNotFoundException {
~ ~
~ ~
return new User( username, password, ~ ~ , authorities);
}
}
SpringSecurity에서 제공하는 UserDetails인터페이스를 구현한 User(사용자의 계정정보와 권한을 담아서)를 반환
thymeleaf-extras-springsecurity5
사용자의 Role에따라 보이는 메뉴를 다르게 함
-----------
<a sec:authorize="isAnonymous()" th:href="@{/user/login}">로그인</a>
------
해당 uri로 이동
<a sec:authorize="isAuthenticated()" th:href="@{/user/logout}">로그아웃</a>
인증된 사용자에게 노출
<a sec:authorize="isAnonymous()" th:href="@{/user/signup}">회원가입</a>
익명의 사용자에게 노출
<a sec:authorize="hasRole('ROLE_MEMBER')" th:href="@{/user/info}">내정보</a>
특정 롤을 가진 사용자에게 노출
<a sec:authorize="hasRole('ROLE_ADMIN')" th:href="@{/admin}">어드민</a>
<span sec:authentication="name"></span>님 환영합니다~
-----------------------
username값을 가져옴
Spring Security가 적용되면 POST 방식으로 보내는 모든 데이터는 csrf 토큰 값이 필요
토큰 값이 없는 상태에서 form 전송을 할 경우, 컨트롤러에 POST 메서드를 매핑할 수 없다는 에러가 발생
<h1>로그인</h1>
<form action="/user/login" method="post">
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
form에 히든 타입으로 csrf 토큰 값을 넘겨준다
<input type="text" name="username" placeholder="이메일 입력해주세요">
로그인 시 아이디의 name 애트리뷰트 값은 username이어야 한다.
<input type="password" name="password" placeholder="비밀번호">
<button type="submit">로그인</button>
</form>
th:action을 사용하면 Thymeleaf가 csrf 토큰 값을 자동으로 추가해줌
---------
<form th:action="@{/user/signup}" method="post">
<input type="text" name="email" placeholder="이메일 입력해주세요">
<input type="password" name="password" placeholder="비밀번호">
<button type="submit">가입하기</button>
</form>