일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
- Spring
- 커스텀 데이터 학습
- marksense.ai
- 순환참조
- pandas
- 2021 제9회 문화공공데이터 활용경진대회
- STT
- matplotlib
- OG tag
- html
- google 로그인
- javascript
- Spring Boot
- @Transactional
- idToken
- skt fellowship 3기
- AWS
- JPA
- oauth
- Loss Function
- YOLOv5
- 졸프
- google cloud
- Expo
- yolo
- 코드업
- C++
- 양방향 매핑
- google login
- react native
- Today
- Total
민팽로그
spring security 본문
spring security?
스프링 서버에 필요한 인증 및 인가를 위한 다양한 기능을 제공하는 프레임워크로 로그인 기능을 구현할 수 있음
- gradle 사용 시 다음을 추가하여 사용할 수 있음
implementation 'org.springframework.boot:spring-boot-starter-security'
- 아래 예시 코드와 같은 형식으로 스프링 시큐리티를 활성화 할 수 있음
@Configuration
@EnableWebSecurity // 스프링 Security 지원을 가능하게 함
@EnableGlobalMethodSecurity(securedEnabled = true) //권한 부여가 가능하게 함
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
//password 암호화를 위한 bean 등록
@Bean
public BCryptPasswordEncoder encodePassword() {
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().disable();
http.authorizeRequests()
// image 폴더를 login 없이 허용
.antMatchers("/images/**").permitAll()
// css 폴더를 login 없이 허용
.antMatchers("/css/**").permitAll()
.antMatchers("/user/**", "/h2-console/**").permitAll()
// 그 외 모든 요청은 인증과정 필요
.anyRequest().authenticated()
.and()
.formLogin()
//로그인 페이지 설정(뷰 템플릿 엔진은 timeleaf 사용했음)
// /user/login 컨트롤러가 login html문서를 내려줌
.loginPage("/user/login")
.loginProcessingUrl("/user/login")
.defaultSuccessUrl("/")
.permitAll()
.and()
.logout()
//로그아웃 컨트롤러는 따로 구현하지 않아도 됨(이미 구현되어 있음)
.logoutUrl("/user/logout")
.permitAll()
.and()
.exceptionHandling()
.accessDeniedPage("/user/forbidden"); //접근 거부 페이지 설정
}
//AuthenticationManager 빈 등록
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
-> default 로그인 시 username은 user이고, password는 서버 시작 시 spring 로그를 통해 알 수 있음.
user 정보 저장 시 password를 DB에 저장하여 관리할 때는 '정보통신망법, 개인정보보호법'에 의해 반드시 암호화를 해야 함.
사진 출처: https://seed.kisa.or.kr/kisa/bbs/faq.do
KISA 암호이용활성화 - 알림마당 - FAQ
알림마당 정보보호의 기반 암호기술 및 정책에 대한 다양한 정보전달 HOME 알림마당 소개 국산 암호기술 암호모듈검증 암호 역기능 대응 자료실 알림마당 FAQ 공지사항 FAQ 1:1문의
seed.kisa.or.kr
스프링 시큐리티에서 제공 및 권고하는 일방향 암호화 알고리즘(암호화는 가능하지만 복호화는 불가능) 중 하나인 BCrypt 해시함수를 사용해 password를 암호화 할 수 있음.
@Bean
public BCryptPasswordEncoder encodePassword() {
return new BCryptPasswordEncoder();
}
-> 빈 등록 후 DI받아 사용하면 됨!
예시 코드)
@Autowired
public UserService(UserRepository userRepository, PasswordEncoder passwordEncoder) {
this.userRepository = userRepository;
this.passwordEncoder = passwordEncoder;
}
...
public String encodingPassword(String pw) {
// 패스워드 인코딩
return passwordEncoder.encode(pw);
}
스프링 시큐리티를 이용한 로그인 기능
1. 스프링 시큐리티를 통한 전체적인 동작 흐름
2. 스프링 시큐리티의 로그인 처리 과정
- 인증/인가 성공 시에만 controller에 회원 정보(UserDetails) 전달
- 인증을 관리하는 역할을 하는 AuthenticationManager가 username을 UserDetails Service에 전달 > UserDetailsService가 username으로 DB를 조회하여 조회된 user 정보를 소유한 UserDetails 생성(조회되지 않는다면 바로 에러 발생) > AuthenticationManager가 ID와 PW를 비교하여 일치한다면 인증 성공 후 인가
- UserDetailsService 인터페이스와 UserDetails 인터페이스를 사용하여 클래스를 구현해 주어야 함(UserDetailsServiceImpl 클래스, UserDetailsImpl 클래스)
UserDetailsServiceImpl 클래스
@Service
public class UserDetailsServiceImpl implements UserDetailsService{
@Autowired
private UserRepository userRepository;
//Authentication Manager로부터 받은 id가 DB에 있는지 확인하고 있다면 유저정보 넘겨줌(패스워드 포함)
//Authentication Manager는 아이디와 비밀번호를 비교하여 일치하면 인증 및 인가함
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("Can't find " + username));
return new UserDetailsImpl(user);
}
}
UserDetailsImpl 클래스
public class UserDetailsImpl implements UserDetails {
private final User user;
public UserDetailsImpl(User user) {
this.user = user;
}
public User getUser() {
return user;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
//스프링 시큐리티는 ROLE_권한 의 형태로 권한을 구분할 수 있음
private static final String ROLE_PREFIX = "ROLE_";
//인가 정보(권한) 부여
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
UserRole userRole = user.getRole();
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(ROLE_PREFIX + userRole.toString());
Collection<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(authority);
return authorities;
}
}
이후 controller에서 로그인된 사용자 정보를 @AuthenticationPrincipal 어노테이션을 통해 사용할 수 있음. @AuthenticationPrincipal 어노테이션을 사용하면 spring security가 로그인된 사용자의 정보를 가져와 넘겨줌.
@GetMapping("/")
public String home(Model model, @AuthenticationPrincipal UserDetailsImpl userDetails) {
List<Folder> folders = folderService.getFolders(userDetails.getUser());
model.addAttribute("folders", folders);
model.addAttribute("username", userDetails.getUsername());
return "index";
}
인가(접근 권한 설정)가 필요한 controller에는 @Secured("{ROLE_이름}")을 추가 + WebSecurityConfigurerAdapter를 상속한 클래스에 @EnableGlobalMethodSecurity(securedEnabled = true) 추가
예시 코드)
@Secured("ROLE_ADMIN")
@GetMapping("/admin")
public String admin(Model model, @AuthenticationPrincipal UserDetailsImpl userDetails) {
model.addAttribute("username", userDetails.getUsername());
model.addAttribute("admin", true);
return "index";
}
마치며
후에 기존 웹 애플리케이션의 로그인 기능에 카카오 소셜 로그인을 추가하게 된다면 세션을 만들어주어 로그인을 하는 강제 로그인 처리가 필요할 수 있다. 이 때 WebSecurityConfig 클래스에서 볼 수 있듯 AuthenticationManager를 사용하게 된다.
// 스프링 시큐리티 통해 인증된 사용자로 등록해주기(세션 생성)
// password를 알 때
Authentication kakaoUsernamePassword = new UsernamePasswordAuthenticationToken(username, password); //id, pw에 대한 인증 토큰 생성
Authentication authentication = authenticationManager.authenticate(kakaoUsernamePassword); //authenticationManager가 토큰을 통해 id와 pw가 일치여부 확인
SecurityContextHolder.getContext().setAuthentication(authentication); //세션 생성 -> 로그인처리 완료
// password를 모를 때
UserDetailsImpl userDetails = new UserDetailsImpl(kakaoUser); //userDetails 정보 가져오기
Authentication authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities()); //pw를 모르므로 userDetails 정보 사용
SecurityContextHolder.getContext().setAuthentication(authentication); //세션 생성 -> 로그인 처리 완료
'🍃spring boot > spring security' 카테고리의 다른 글
spring security (0) | 2021.09.05 |
---|