- @ManytoOne 디폴드 값은 EAGER
끝이 One인것은 모두다 eager ⭐
조회하는 순간 sql다 끌고와서 관련된 테이블 한꺼번에 가지고옴- @OnetoMany는 디폴드값 lAZY (신경x)
- @ManytoOne(fetch=fetchType.lAZY)
필요한 값만 조회하기위에서 lazy꼭 걸어주기⭐- 동시에 조회해야하는것만 EAGER로 걸어줌 .
▶Maven 방식 (실무에선 거의 사용x)
🔽 환경셋팅 해주기
package com.oracle.oBootSecurity01.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
public class SecurityController01 {
@GetMapping("/user")
public String user() {
System.out.println("SecurityController01 user start . . . . . ");
return "user";
}
@GetMapping("/manager")
public String manager() {
System.out.println("SecurityController01 user start . . . . . ");
return "manager";
}
@GetMapping("/admin")
public String admin() {
System.out.println("SecurityController01 user start . . . . . ");
return "admin";
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>manager 인증 성공</h1>
</body>
</html>
----------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>admin 인증 성공</h1>
</body>
</html>
--------------------------
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>user 인증 성공</h1>
</body>
</html>
🔽실행시
package com.oracle.oBootSecurity01.configuration;
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.configuration.EnableWebSecurity;
//IoC 빈(bean)을 등록
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity //필터 체인 관리 시작 어노테이션
public class SecurityConfig {
@Bean
//해쉬암호화
public BCryptPasswordEncoder encoderPwd() {
return new BCryptPasswordEncoder();
}
@Bean
protected SecurityFilterChain securityFilterChain (HttpSecurity http) throws Exception {
http.csrf().disable(); //비활성화
http.authorizeHttpRequests()
.anyRequest()
.permitAll();
return http.build();
}
}
🔽로그인페이지 안뜨고 바로 들어와짐
@Autowired
//암호화
private BCryptPasswordEncoder bCryptPasswordEncoder;
@GetMapping("/user")![](https://velog.velcdn.com/images/rhdguswlx/post/dc16337e-82a8-4d05-bbf1-ef40b2a5ecd1/image.gif)
public String user(String passwd) {
System.out.println("SecurityController01 user start . . . . . ");
System.out.println("SecurityController01 user passwd->"+passwd);
//해쉬 암호화
String encPasswd = bCryptPasswordEncoder.encode(passwd);
System.out.println("SecurityController01 user encPasswd->"+encPasswd);
return "user";
}
▶실무에선 Gradle방식 사용
▶security 사용할땐 configuration 도 생성해주기
▶보통의미
dto 라고 정의하면 --> mybatis
dmmain/entity라고 정의하면 --> jpa
package com.oracle.oBootSecurity02.entity;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import org.hibernate.annotations.CreationTimestamp;
import lombok.Data;
@Entity
@Data
@SequenceGenerator(
name = "user_seq_gen",
sequenceName = "user_seq_generator",
initialValue = 1,
allocationSize = 1
)
@Table(name = "user01")
public class User {
@Id // primary Key
@GeneratedValue(
strategy = GenerationType.SEQUENCE,
generator = "user_seq_gen"
)
private int id;
private String username;
private String password;
private String email;
private String role; // ROLE_USER, ROLE_ADMIN, ROLE_MANAGER
@CreationTimestamp //INSERT 시 자동으로 값을 채워줌
private Timestamp createDate;
}
인터페이스생성
package com.oracle.oBootSecurity02.repository;
import org.springframework.stereotype.Repository;
import com.oracle.oBootSecurity02.entity.User;
@Repository
public interface SecurityRepository {
void save(User user);
User findByUsername(String username);
// Username을 where 조건절에 넣어 데이터를 가져올 수 있도록 findByUsername 정의
}
.`
SecurityRepository 상속받아 class생성
package com.oracle.oBootSecurity02.repository;
import javax.persistence.EntityManager;
import org.springframework.stereotype.Repository;
import com.oracle.oBootSecurity02.entity.User;
import lombok.RequiredArgsConstructor;
import lombok.ToString;
@Repository
@RequiredArgsConstructor
public class JpaSecurityRepository implements SecurityRepository {
private final EntityManager em;
@Override
public void save(User user) {
em.persist(user);
}
//username -->unique 라 가정
@Override
public User findByUsername(String username) {
User user = em.createQuery("select u from User u where username = :username", User.class)
.setParameter("username", username)
.getSingleResult();
return user;
}
}
인터페이스생성
package com.oracle.oBootSecurity02.service;
import org.springframework.stereotype.Service;
import com.oracle.oBootSecurity02.entity.User;
@Service
public interface SecurityService {
User findByUsername(String username);
void save(User user);
}
SecurityService 상속받아 class생성
package com.oracle.oBootSecurity02.service;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.oracle.oBootSecurity02.entity.User;
import com.oracle.oBootSecurity02.repository.JpaSecurityRepository;
import lombok.RequiredArgsConstructor;
@Service
@RequiredArgsConstructor
@Transactional
public class SecurityServiceImpl implements SecurityService {
private final JpaSecurityRepository jpaSecurityRepository;
@Override
public User findByUsername(String username) {
User user = jpaSecurityRepository.findByUsername(username);
return user;
}
@Override
public void save(User user) {
System.out.println("SecurityServiceImpl save start . . . ");
jpaSecurityRepository.save(user);
}
}
package com.oracle.oBootSecurity02.controller;
import java.security.Principal;
import java.util.Iterator;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import com.oracle.oBootSecurity02.configuration.auth.PrincipalDetails;
import com.oracle.oBootSecurity02.entity.User;
import com.oracle.oBootSecurity02.service.SecurityService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@Controller
@Slf4j
@RequiredArgsConstructor
public class SecurityController02 {
private final SecurityService securityServiceImpl; //bean으로 등록되어있음 -> @service걸려있기때문에
private final BCryptPasswordEncoder bCryptPasswordEncoder; //암호화 사용하기위해서
// BCryptPasswordEncoder 는 빈 설정해줘야함
@GetMapping("/user")
public String user(@AuthenticationPrincipal PrincipalDetails Principal ) {
System.out.println("SecurityController02 user start . . . . . ");
System.out.println("SecurityController02 user principar-> " +Principal);
Iterator<? extends GrantedAuthority> iter = Principal.getAuthorities().iterator();
while (iter.hasNext()) {
GrantedAuthority authority = iter.next();
System.out.println("authority.getauthority()->"+authority.getAuthority());
} ![](https://velog.velcdn.com/images/rhdguswlx/post/19446cf8-ed08-4b63-bc39-c6c844192139/image.png)
return "user";
}
/*
* public String user(String passwd) {
* System.out.println("SecurityController01 user start . . . . . ");
* System.out.println("SecurityController01 user passwd->"+passwd); //해쉬 암호화
* String encPasswd = bCryptPasswordEncoder.encode(passwd);
* System.out.println("SecurityController01 user encPasswd->"+encPasswd); return
* "user"; }
*/
@GetMapping("/user/2")
public String user2(String passwd) {
System.out.println("SecurityController02 user start . . . . . ");
return "user";
}
@GetMapping("/manager")
public String manager() {
System.out.println("SecurityController02 manager start . . . . . ");
return "manager";
}
@GetMapping("/manager/2")
public String manager2() {
System.out.println("SecurityController02 manager2 start . . . . . ");
return "manager";
}
@GetMapping("/admin")
public String admin() {
System.out.println("SecurityController02 user start . . . . . ");
return "admin";
}
@GetMapping("/admin/2")
public String admin2() {
System.out.println("SecurityController02 admin2 start . . . . . ");
return "admin";
}
//로그인실패시
@GetMapping("/loginFail")
public String loginFail() {
System.out.println("loginFail start. . . ");
return "loginFail";
}
//로그인시
@GetMapping("/loginForm")
public String loginForm() {
System.out.println("SecurityController02 loginForm진행 . . . ");
return "loginForm";
}
//user등록 form
@GetMapping("/joinForm")
public String joinForm() {
System.out.println("SecurityController02 joinForm진행 . . . ");
return "joinForm";
}
//진짜 user등록
@PostMapping("/joinProc")
public String joinProc(User user) {
System.out.println("회원가입 진행:" + user);
//spring security 권장-- >passwd암호화
String encPasswd = bCryptPasswordEncoder.encode(user.getPassword()); //사용자가 적은 패스워드
user.setPassword(encPasswd);
securityServiceImpl.save(user);
return "redirect:/loginForm ";
}
}
package com.oracle.oBootSecurity02.configuration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
@Configuration //Ioc 빈(Bean) 을 등록
@EnableWebSecurity //Spring Security 설정 클래스임을 알려줌
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true) //특정 주소로 접근하면 권한 및 인증을 미리 체크하기 위해 사용
public class SecurityConfig {
// 비밀번호를 암호화해서 사용할 수 있도록 Bean으로 등록함
@Bean //비밀번호 암호화 객체
public BCryptPasswordEncoder encodePwd() {
return new BCryptPasswordEncoder();
}
//
@Bean
protected SecurityFilterChain
//HttpSecurity를 통해 HTTP 요청에 대한 보안을 구성할 수 있다.
filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
//csrf 토큰 없이 요청하면 해당 요청을 막기 때문에 잠깐 비활성화해주었다.
http.authorizeRequests()
//HttpServletRequest에 따라 접근을 제한한다
.antMatchers("/user/**")
//user로 시작하는 경로에 접근가능
.authenticated() // /user/** 은 인증 필요 --> 인증만 되면 들어갈 수 있다.
.and()
.formLogin()
//form 기반으로 인증한다. /login 경로로 접근하면, Spring Security에서 제공하는 로그인 Form을 사용할 수 있다
.loginPage("/loginForm")
//기본으로 제공되는 form 말고, 커스텀 로그인 폼을 사용하기 위해 loginPage() 메소드를 사용했다.
.loginProcessingUrl("/login")
//Security에서 해당 주소로 오는 요청을 낚아채서 수행한다.
.failureUrl("/loginFail")
//로그인 실패시 이동하는 페이지
.defaultSuccessUrl("/");
//로그인성공시 이동되는 페이지
return http.build();
}
}
package com.oracle.oBootSecurity02.configuration.auth;
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;
import org.springframework.transaction.annotation.Transactional;
import com.oracle.oBootSecurity02.entity.User;
import com.oracle.oBootSecurity02.repository.JpaSecurityRepository;
import com.oracle.oBootSecurity02.repository.SecurityRepository;
import lombok.RequiredArgsConstructor;
@Service
@Transactional
@RequiredArgsConstructor
//DB에 담긴 사용자 인증정보와 비교하기 위해 UserDetailsService에 사용자 정보를 넘겨줌
//Security 설정에서 loginProcessingUrl("/login")
//login 요청이 오면 자동으로 UserDetailsService Type으로
//IOC되어 있는 loadUserByUsername Method가 실행(약속)
//Security session( 내부-> Authentication(내부->userDetails) )
public class PrincipalDetailsService implements UserDetailsService {
private final SecurityRepository jpaSecurityRepository;
/* username이 DB에 있는지 확인 */
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("PrincipalDetailsService username : "+username);
User user = jpaSecurityRepository.findByUsername(username);
if(user== null) return null;
else return new PrincipalDetails(user);
} /* 시큐리티 세션에 유저 정보 저장 */
}
package com.oracle.oBootSecurity02.configuration.auth;
import java.util.ArrayList;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import com.oracle.oBootSecurity02.entity.User;
import lombok.Data;
//Authentication 객체에 저장할 수 있는 유일한 타입
@Data
public class PrincipalDetails implements UserDetails {
private User user;
public PrincipalDetails (User user) {
this.user = user;
System.out.println("PrincipalDetails 생성자 getUsername--> "+user.getUsername());
}
@Override
//해당 user의 권한을 리턴하는곳.
/* 유저의 권한 목록 */
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collect = new ArrayList<>();
collect.add(new GrantedAuthority() {
@Override
public String getAuthority() {
System.out.println("getAuthorities GrantedAuthority user.getRole()--> "+user.getRole());
return user.getRole();
}
});
return collect;
}
@Override
public String getPassword() {
// TODO Auto-generated method stub
return user.getPassword();
}
@Override
public String getUsername() {
// TODO Auto-generated method stub
return user.getUsername();
}
/* 계정 만료 여부
* true : 만료 안됨
* false : 만료
*/
@Override
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
/* 계정 잠김 여부
* true : 잠기지 않음
* false : 잠김
*/
@Override
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
/* 비밀번호 만료 여부
* true : 만료 안됨
* false : 만료
*/
@Override
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
/* 사용자 활성화 여부
* true : 만료 안됨
* false : 만료
*/
@Override
// 예시 ->1년동안 Login 안한 사람 휴먼 계정 ->return false
public boolean isEnabled() {
// TODO Auto-generated method stub
return true;
}
}
index.html
Insert title here
loginFail.html
Insert title here
loginForm.html
Insert title here
joinForm.html
Insert title here
비번 :
email :
권한 : 일반유저 관리자 admin 회원가입
user.html
Insert title here
id는 자동생성됨
🔽암호화되어서 비밀번호 들어감
암호화의 목적 -->확산과 혼돈