티스토리 뷰
spring boot JWT 인증 #2 (model, repository, userDetails, configAdapter)
coor 2021. 8. 17. 11:021. model 생성
- User
@Data
@Entity
@Table( name = "users",
uniqueConstraints = {
@UniqueConstraint(columnNames = "username"),
@UniqueConstraint(columnNames = "email")
})
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@NotBlank
@Size(max = 20)
private String username;
@NotBlank
@Size(max = 50)
@Email
private String email;
@NotBlank
@Size(max = 120)
private String password;
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable( name = "user_roles",
joinColumns = @JoinColumn(name = "user_id"),
inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<>();
- 테이블 이름은 user
- username, email은 동일한 값을 넣지 않기 위해서 @UniqueConstraint 추가
- 데이터에 null , "" , " " 값을 넣지 않기 위해서 @NotBlank 추가
- id는 데이터가 한개씩 생성될 때마다 +1씩 증가
- 다른 테이블을 생성하고 조인하기 위해서 @JoinTable
- @ManyToMany(fetch = FetchType.LAZY)는
부모를 조회하면 자식은 조회되지 않는다. 자식은 프록시 객체로 된다.
실제 사용될 때까지 DB를 조회하지 않고 데이터 로딩을 미뤄 지연로딩하게 된다.
데이터가 필요한 순간이 되어서야 DB에 조회해서 프록시 객체를 초기화한다.
- ERole
public enum ERole {
ROLE_USER,
ROLE_MODERATOR,
ROLE_ADMIN
}
- Role
@Data
@Entity
@Table(name = "roles")
public class Role {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Enumerated(EnumType.STRING)
@Column(length = 20)
private ERole name;
- roles 테이블에 각 유저 권한을 주기위한 테이블
2. repository 생성
- RoleRepository
@Repository
public interface RoleRepository extends JpaRepository<Role, Long> {
Optional<Role> findByName(ERole name);
}
사용자의 권한을 찾기 위한 findByName
- UserRepository
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsername(String username);
Boolean existsByUsername(String username);
Boolean existsByEmail(String email);
}
3. UserDetails 생성
- UserDetailsImpl
public class UserDetailsImpl implements UserDetails {
private static final long serialVersionUID = 1L;
private Long id;
private String username;
private String email;
@JsonIgnore
private String password;
private Collection<? extends GrantedAuthority> authorities;
public UserDetailsImpl(Long id, String username, String email, String password,
Collection<? extends GrantedAuthority> authorities) {
this.id = id;
this.username = username;
this.email = email;
this.password = password;
this.authorities = authorities;
}
public static UserDetailsImpl build(User user) {
List<GrantedAuthority> authorities = user.getRoles().stream()
.map(role -> new SimpleGrantedAuthority(role.getName().name()))
.collect(Collectors.toList());
return new UserDetailsImpl(
user.getId(),
user.getUsername(),
user.getEmail(),
user.getPassword(),
authorities);
}
- UserDetails 상속
- private static final long serialVersionUID = 1L 는
serialVersionUID는 직렬화와 역직렬화를 가능
클래스에 새로운 맴버(authorities)를 추가해도 오류가 발생하지 않는다. -> null 값으로 초기화
- UserDetailsServiceImpl
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
UserRepository userRepository;
@Override
@Transactional
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("아이디 확인중");
User user = userRepository.findByUsername(username)
.orElseThrow(() -> new UsernameNotFoundException("User Not Found with username: " + username));
return UserDetailsImpl.build(user);
}
}
- AuthenticationManager 로그인 시도를 하면 UserDetailsServiceImpl의 loadUserByUsername 실행
- userRepository.findByUsername(username) DB의 username을 확인
- 회원이 없을 경우 "User Not Found with username" 호출
- 리턴을 통해 username의 값을 UserDetailsImpl 보냄
- password 체크는 나중에 controller에서 AuthenticationManager.authenticate(Authentication)을 호출하면 내부적으로 처리를 함
3. 생성
- WebSecurityConfig
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
......
@Override
protected void configure(HttpSecurity http) throws Exception {
http.cors().and().csrf().disable()
.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/api/auth/**").permitAll()
.antMatchers("/api/test/**").permitAll()
.anyRequest().authenticated();
http.addFilterBefore(authenticationJwtTokenFilter(), UsernamePasswordAuthenticationFilter.class);
}
}
WebSecurityConfig는 사용자 인증에 대한 정보를 포함한다.
- 사용자가 인증을 하기 위해 조건을 추가
- 로그인 폼을 사용/미사용
- Http기반 인증/비인증
- CORS 정책 설정
- antMachers 경로 설정
- sessionManagement 세션 설정
- addFilterBefore 필터 설정
'∙React + Spring' 카테고리의 다른 글
회원가입,로그인,로그아웃 기능,경로 설정(react + spring boot ) (0) | 2021.08.17 |
---|---|
spring boot JWT 인증 #4 (Controller) (0) | 2021.08.17 |
spring boot JWT 인증 #3 ( 비인증, 필터, JWT 생성) (0) | 2021.08.17 |
spring boot JWT 인증 #1 (0) | 2021.08.17 |