대부분의 웹 프로젝트는 인증 시스템을 가지고 있다. 작게는 경로를 설정해두었지만 특정한 사람만 들어오도록 하는 것이고 많이 쓰이는 인증 시스템으로는 로그인 한 유저만 볼 수 있는 페이지를 만드는 것이다.
spring security는 spring 기반의 보안 담당 프레임워크이다. 인증과 권한에 대한 부분을 filter의 흐름에 따라 처리하고 있다. 경로에 대한 Role 설정 및 로그인 시스템 및 페이지 등을 자동으로 처리해주어 편하다.
먼저 spring security를 사용하기 위해서는 gradle을 추가해야 한다.
// web security 관련
implementation 'org.springframework.boot:spring-boot-starter-security'
기본적인 security 설정 클래스이다. 어노테이션으로 Configuration 과 EnbaleSecurity가 꼭 들어가줘야 한다.
package com.jelly_develop.passprofile.role.login;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/templates/**\",\"/resources/**","/css/**","/image/**","/js/**");
}
@Override
protected void configure(HttpSecurity http) throws Exception{
http.headers().frameOptions().sameOrigin();
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/[경로]").permitAll()
.antMatchers("/[경로]").permitAll()
.antMatchers("/[경로]/**").permitAll()
.antMatchers("/[경로]").hasRole("MEMBER")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/[경로]")
.loginProcessingUrl("/[경로]")
.defaultSuccessUrl("/")
.and()
.logout();
}
}
package com.jelly_develop.passprofile.role.login;
import com.jelly_develop.passprofile.domain.member.Member;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
//Security Session => Authentication => UserDetails
public class PrincipalDetails implements UserDetails {
private Member member; // 콤포지션
public PrincipalDetails(Member member) {
this.member = member;
}
// 해당 USER의 권한을 return하는 곳
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
List<GrantedAuthority> auth = new ArrayList<>();
auth.add(new SimpleGrantedAuthority(member.getRole()));
return auth;
}
@Override
public String getPassword() {
return member.getPassword();
}
@Override
public String getUsername() {
return member.getEmail();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
// 우리 사이트에서 1년동안 회원이 로그인을 안하면 휴면계정으로 하기로 했다면
return true;
}
//private final MemberRepository memberRepository;
}
###Spring Security 인증 진행 순서
UserDetailsService는 인증 프로세스와 같으며 loadUserByUsername을 override 인증 프로세스를 진행합니다.
package com.jelly_develop.passprofile.role.login;
import com.jelly_develop.passprofile.domain.member.Member;
import com.jelly_develop.passprofile.repository.member.MemberRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
@RequiredArgsConstructor
@Slf4j
public class PrincipalDetailsService implements UserDetailsService {
private final MemberRepository memberRepository;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Member memberEntity = memberRepository.findByEmail(username);
if (memberEntity != null) {
System.out.println("memberEntity = " + memberEntity.getEmail());
return new PrincipalDetails(memberEntity);
}
return null;
}
}
<div class="wrapper">
<div class="logo"> <img src="https://www.freepnglogos.com/uploads/twitter-logo-png/twitter-bird-symbols-png-logo-0.png" alt=""> </div>
<div class="text-center mt-4 name"> PassProfile </div>
<form class="p-3 mt-3" action="/login" method="post">
<div class="form-field d-flex align-items-center"> <span class="far fa-user"></span> <input type="text" name="username" placeholder="Email"> </div>
<div class="form-field d-flex align-items-center"> <span class="fas fa-key"></span> <input type="password" name="password" placeholder="Password"> </div>
<button class="btn mt-3">Login</button>
</form>
<div class="text-center fs-6"> <a href="#">Forget password?</a> or <a href="/signup">Sign up</a> </div>
</div>
[Python] kwargs 파라미터시 dict 데이터 넘기기 (0) | 2022.04.07 |
---|---|
[SQL] View Table 생성, 삭제, 손쉽게 알아보자 (0) | 2022.04.05 |
[Angular js] 기본 문법 정리, 실습에서 바로 활용할 수 있게 (0) | 2022.03.30 |
[ubuntu] 리눅스 mariadb 초기 설정 및 외부 접속 방법 (0) | 2022.03.30 |
Chrome Extension storage 사용 방법 및 정리 (0) | 2022.03.29 |