스프링 시큐리티 2.7.5
view는 JSP를 사용할 것이기에 미리 추가해둡니다.
/* Spring Security */
implementation 'org.springframework.boot:spring-boot-starter-security'
testImplementation 'org.springframework.security:spring-security-test'
/* Spring security taglib for JSP */
implementation 'org.springframework.security:spring-security-taglibs'
Spring Security의 설정을 진행합니다.
package com.iraefolio.config;
import com.iraefolio.service.security.CustomUserDetailsService;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Log4j2
@RequiredArgsConstructor
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig {
/* 자원 접근 조정 및 csrf 토근 관리 */
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
/* 로그인 페이지 지정 */
http.formLogin().loginPage("/login").defaultSuccessUrl("/");
http.logout().logoutSuccessUrl("/");
/* CSRF 비활성화 */
http.csrf().disable();
return http.build();
}
/* 정적 자원 허용 */
@Bean
public WebSecurityCustomizer webSecurityCustomizer() {
return (web -> web.ignoring().requestMatchers(PathRequest.toStaticResources().atCommonLocations()));
}
/* 비밀번호 인코더 */
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
package com.iraefolio.service.security;
import com.iraefolio.domain.Member;
import com.iraefolio.mapper.AccountMapper;
import lombok.NoArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Log4j2
@RequiredArgsConstructor
@Service
public class CustomUserDetailsService implements UserDetailsService {
private final AccountMapper accountMapper;
/* 회원 가입 */
public boolean create(Member member){
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
member.setUsername(member.getUsername());
member.setPassword(passwordEncoder.encode(member.getPassword()));
member.setName(member.getName());
boolean result = accountMapper.create(member);
return result;
}
/* 로그인 */
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Optional<Member> result = accountMapper.findByUserName(username);
if (result.isEmpty()) throw new UsernameNotFoundException("not found");
Member member = result.get();
return member;
}
}
package com.iraefolio.domain;
import lombok.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Collectors;
@Setter
@Getter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@ToString(exclude = "roleSet")
public class Member implements UserDetails {
private String username;
private String password;
private String name;
private String role;
private boolean del;
private boolean social;
public void changePassword(String password) {
this.password = password;
}
public void changeName(String name) {
this.name = name;
}
public void changeDel(boolean del) {
this.del = del;
}
public void changeSocial(boolean social) {
this.social = social;
}
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return Collections.singletonList(new SimpleGrantedAuthority(this.role));
}
@Override
public boolean isAccountNonExpired() {
return !del;
}
@Override
public boolean isAccountNonLocked() {
return !del;
}
@Override
public boolean isCredentialsNonExpired() {
return !del;
}
@Override
public boolean isEnabled() {
return !del && !social;
}
}
<%@ page language="java" contentType="text/html;charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<!-- 사용자 정보 -->
<sec:authorize access="isAuthenticated()">
<sec:authentication property="principal" var="user"/>
</sec:authorize>
<!-- JS 전달용 -->
<script type="text/javascript">
let currentUser = '${user}';
</script>