§ 스프링 시큐리티 권한/인증 설정
: 권한 관리 / 인증 규칙을 정의하는 곳
예) 부서는 일반 유저가 볼수 있음, 갤러리는 관리자만 볼수있음 (권한 관리)

: 자바 파일을 스프링의 환경 설정을 할수 있게 하는 어노테이션
: 자바 설정파일의 함수 위에 붙여서 IOC 를 해주는 어노테이션
(IOC : 스프링을 객체를 생성해주는 기능)
-WebSecurityConfig.java
→ 로그인화면(기본화면: 스프링 시큐리티 라이브러리에서 제공함)
→ WebSecurityConfig.java filterChain() 에서 인증 설정하면 화면 볼 수 있음
인증(authority)
: 로그인시 적절한 사용자인지 확인하는 절차
인가(authentication)
: 로그인은 했지만 일정 권한을 가진 사람만 특정 화면을 볼 수 있는 권리, 권한관리라고도 함
: 권한 설정(==인가) (사용자/관리자 권한에 따라 화면을 볼 수 있는 설정)
: 인증(로그인: ID , PassWord)
.requestMatchers("url 경로").permitAll();
: /auth/ 아래 url 만 접근 가능
.requestMatchers("url 경로").hasRole("ADMIN"); // 관리자만 사용 가능
.requestMatchers("/**").hasRole("ADMIN") // /ROLE_ADMIN 권한을 가진 자만 접근가능
.requestMatchers("/**").permitAll(); // 루뜨 뒤에 있는 모든 사용자 접근 권한을 허용
return http.build();
}
1) 쿠키/세션 인증 : 전통적인 인증방식으로 주로 JSP 등을 이용하는 프로그램에서 사용하며, 관련 해킹공격이 있으므로 방어에 유의해야함 (csrf 해킹 공격)
쿠키 : 웹브라우저에서 기본적으로 제공하는 저장공간 : 주로 민감 보안외의 정보를 넣어서 관리
세션 : 서버에서 정상적인 유저로 확인되면 세션이라는 공간에 인증 정보를 저장하고 세션ID 를 발급해서 쿠키에 넣어 유저에게 전송함, 유저는 로그인 후 다른 화면을 검색할때 정상적인 유저임을 확인하기 위해 항상 쿠키안의 세션id 를 확인함 (쿠키는 서버로 자동전송됨)
인증절차
1) 로그인 버튼을 클릭하면 유저/암호 정보를 spring 서버로 전송
2) spring 서버에서 정상적인 유저인지 DB 에서 확인 : 스프링 시큐리티 인증
3) 확인되면 세션ID 를 발급해서 쿠키에 넣어 유저의 웹브라우저로 전송
4) 유저는 이제 세션ID 가 있는 쿠키를 가지고 해당 웹사이트의 화면을 볼수 있음
=> 상기의 모든 절차는 spring security 에서 몇가지 설정에 의해 자동으로 모두 이루어지며 기본으로 작동되어 코딩은 필요없음
=> 단, 쿠키/세션에 대한 csrf 해킹공격이 있으므로 방어를 위해 csrf 토큰인증을 추가로 진행해야함
☆ 인증 방식 : jsp : 쿠키/세션 방식을 사용

1) 로그인 설정
1) 로그인 설정
http.formLogin() // 스프링시큐리티에서 제공하는 로그인화면
.loginPage("/auth/customLogin") // 기본로그인화면 대신 개발자가 만든 화면 사용 (새 로그인페이지)
.loginProcessingUrl("/auth/login")
// => 로그인 버튼(jsp) 클릭 시 실행될 함수 url (스프링시큐리티가 자동실행함,
// 컨트로러 함수 불필요함,
// 기본정보 : user 객체 정보 제공)
.defaultSuccessUrl("/"); // 로그인 성공하면 강제 이동할 페이지
2) 로그아웃 설정
http.logout()
.logoutUrl("auth/customLogout") // 로그아웃 진행
// 로그아웃 처리 진행 : 스피링시큐리티가 자동으로 진행함
// 아래 url : jsp 에서 클릭시 로그아웃 진행됨 : post 방식(로그인/로그아웃 동일)(숨겨서 백엔드로 전송)
.invalidateHttpSession(true) // 세션 ID 무효화 == 세션 ID 제거
.logoutSuccessUrl("/"); // 로그아웃 성공하면 강제 이동할 페이지
-Member.java
@Entity
@Table(name = "TB_MEMBER")
@DynamicInsert
@DynamicUpdate
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@ToString
// soft delete jpa 어노테이션
@Where(clause = "DELETE_YN = 'N'")
@SQLDelete(sql = "UPDATE TB_MEMBER SET DELETE_YN = 'Y', DELETE_TIME=TO_CHAR(SYSDATE, 'YYYY-MM-DD HH24:MI:SS') WHERE EMAIL = ?")
public class Member extends BaseTimeEntity2 {
@Id
private String email; // 로그인 id (스프링시큐리티 속성 : username)
private String password; // 암호
private String name; // 유저명
private String code_name; // 권한명: ROLE_USER(사용자), ROLE_ADMIN(관리자)
}
public interface MemberRepository extends JpaRepository<Member, String> {
}
@Service
public class MemberService {
@Autowired
private MemberRepository memberRepository; // DI
// TODO: 로그인 관련 함수
// 상세조회
public Optional<Member> findById(String email) {
Optional<Member> optionalMember
= memberRepository.findById(email);
return optionalMember;
}
}
: IOC (스프링이 객체를 생성해주는 것), 함수의 리턴객체를 생성함
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
-MemberController
@Autowired
MemberService memberService; // DI
@Autowired
PasswordEncoder passwordEncoder; // 암호화 객체 DI
로그인
1) 로그인 페이지 열기 함수(제작)
=> WebSecurityConfig.java filterChain() 함수안에 정의
@GetMapping("/customLogin")
public String login() {
return "auth/customLogin.jsp";
}
2) 로그인 버튼 클릭하면 실행될 함수(안만듬, 스프링자동) => jsp : form action="/auth/login"
=> WebSecurityConfig.java filterChain() 함수안에 정의
=> DB에 사용자가 있는지 확인하는 함수 (개발자가 작성)
=> 스프링이 인증할때 그 함수를 자동 실행
=> DB 확인해서 정상사용자인지 검증이 끝나면 --> 검증객체에 넣음(개발자 작성)

-MemberDto
@Setter
@Getter
@ToString
public class MemberDto extends User {
// 개발자 추가 속성(필드) : email
private String email; // 로그인 ID == username
// 생성자 : 자동생성 : alt + insert(cmd + n)
// 권한이 배열로 되어있다.
public MemberDto(String email, String password, Collection<? extends GrantedAuthority> authorities) {
super(email, password, authorities);
this.email = email;
}
}
-UserDetailsServiceImpl
① 유저 DB 인증 : 상세조회
옵셔널객체.orElseThrow(new 예외처리클래스("에러메세지"));@Service
public class UserDetailsServiceImpl implements UserDetailsService {
// DB Member 레포지토리 DI
@Autowired
MemberRepository memberRepository;
// 함수 재정의 : 자동 기능 : alt + insert
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
// TODO: 1) 유저 DB 인증 : 상세조회
// js 화살표 함수 : function(x){return x+1;} : (x) => x + 1;
// java 람다식 : interface x(함수()) : (x) -> x + 1;
// 사용법 : 옵셔널객체.orElseThrow(new 예외처리클래스("에러메세지"));
// => 옵셔널객체의 결과가 null 이면 에러메세지 출력, 아니면 변수에 저장됨
Member member
= memberRepository.findById(email)
.orElseThrow(() -> new UsernameNotFoundException("email 없음:" + email));
return null;
}
}
-costomlogin.jsp
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>- 예) 로그인/로그아웃, 부서추가/수정, 사원추가/수정 등
