한솔이 노션 https://boulder-hippodraco-244.notion.site/Spring-Security-5c96bcae888547ce98d526f0e1901d34
☑️ user, roles, user DB setting 및 JPA setting
1. DB schema setting
- user table
- roles table
- user_role table
2. JPA setting
✅ build.gradle
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
|
plugins {
id 'java'
id 'org.springframework.boot' version '3.2.2'
id 'io.spring.dependency-management' version '1.1.4'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
java {
sourceCompatibility = '17'
}
repositories {
mavenCentral()
}
dependencies {
implementation 'org.springframework.boot:spring-boot-starter'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-web'
//lombok사용
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
//Mapstruct
implementation 'org.mapstruct:mapstruct:1.5.5.Final'
annotationProcessor 'org.mapstruct:mapstruct-processor:1.5.5.Final'
//Swagger
implementation 'io.springfox:springfox-swagger-ui:3.0.0'
implementation 'io.springfox:springfox-swagger2:3.0.0'
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'
//env-hide
annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor'
//mariadb
implementation 'org.mariadb.jdbc:mariadb-java-client:3.1.4'
//JPA
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
//jwt
implementation 'io.jsonwebtoken:jjwt:0.9.1'
//security
// implementation 'org.springframework.boot:spring-boot-starter-security'
// //javax.xml.bind.DatatypeConverter 에러나서 해야됨⬇️
// implementation 'javax.xml.bind:jaxb-api:2.3.1'
runtimeOnly 'mysql:mysql-connector-java:8.0.26'
//security 무슨 에러 난다는거지?
implementation 'org.springframework.boot:spring-boot-starter-security'
}
tasks.named('test') {
useJUnitPlatform()
}
|
✅ application.yaml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
datasource:
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/BackEndProject_2_verSoh?useUnicode=true&characterEncoding=UTF-8
jpa:
show-sql: true
jwtpassword:
source: ${JWT_SECRET_KEY}
logging:
level:
org.hibernate.SQL: debug
|
💡 autoconfig를 추가하면 jpaConfig, DataSourceProperties를 추가하지 않아도 된다.
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
| server:
port:8080
spring:
mvc:
pathmatch:
matching-strategy: ant_path_matcher
autoconfigure:
exclude: org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
datasource:
username: ${DATABASE_USERNAME}
password: ${DATABASE_PASSWORD}
driver-class-name: org.mariadb.jdbc.Driver
url: jdbc:mysql://localhost:3306/BackEndProject_2_verSoh?useUnicode=true&characterEncoding=UTF-8
jpa:
show-sql: true
jwtpassword:
source: ${JWT_SECRET_KEY}
logging:
level:
org.hibernate.SQL: debug
|
✅ JPAConfig
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
| package com.example.supercoding2stsohee.config;
import com.example.supercoding2stsohee.config.properties.DataSourceProperties;
import jakarta.persistence.EntityManagerFactory;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.JpaVendorAdapter;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter;
import org.springframework.transaction.PlatformTransactionManager;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
@Configuration
@EntityScan
@EnableConfigurationProperties(DataSourceProperties.class)
@RequiredArgsConstructor
@EnableJpaRepositories(
basePackages = {"com.example.supercoding2stsohee.repository.cart",
"com.example.supercoding2stsohee.repository.orderItem",
"com.example.supercoding2stsohee.repository.orderTable",
"com.example.supercoding2stsohee.repository.product",
"com.example.supercoding2stsohee.repository.productOption",
"com.example.supercoding2stsohee.repository.productPhoto",
"com.example.supercoding2stsohee.repository.review",
"com.example.supercoding2stsohee.repository.roles",
"com.example.supercoding2stsohee.repository.userRoles",
"com.example.supercoding2stsohee.repository.user"
},
entityManagerFactoryRef = "localContainerEntityManagerFactoryBean",
transactionManagerRef = "tm"
)
public class JpaConfig {
private final DataSourceProperties dataSourceProperties;
@Bean
public DataSource dataSource() {
DriverManagerDataSource driverManagerDataSource = new DriverManagerDataSource();
driverManagerDataSource.setUrl(dataSourceProperties.getUrl());
driverManagerDataSource.setUsername(dataSourceProperties.getUsername());
driverManagerDataSource.setPassword(dataSourceProperties.getPassword());
driverManagerDataSource.setDriverClassName(dataSourceProperties.getDriverClassName());
return driverManagerDataSource;
}
@Bean
public LocalContainerEntityManagerFactoryBean localContainerEntityManagerFactoryBean(DataSource datasource) {
LocalContainerEntityManagerFactoryBean lemfb = new LocalContainerEntityManagerFactoryBean();
lemfb.setDataSource(datasource);
lemfb.setPackagesToScan(
"com.example.supercoding2stsohee.repository.cart",
"com.example.supercoding2stsohee.repository.orderItem",
"com.example.supercoding2stsohee.repository.orderTable",
"com.example.supercoding2stsohee.repository.product",
"com.example.supercoding2stsohee.repository.productOption",
"com.example.supercoding2stsohee.repository.productPhoto",
"com.example.supercoding2stsohee.repository.review",
"com.example.supercoding2stsohee.repository.roles",
"com.example.supercoding2stsohee.repository.userRoles",
"com.example.supercoding2stsohee.repository.user"
);
JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
lemfb.setJpaVendorAdapter(vendorAdapter);
Map<String, Object> properties = new HashMap<>();
properties.put("hibernate.dialect", "org.hibernate.dialect.MariaDBDialect");
properties.put("hibernate.format_sql", "true");
properties.put("hibernate.use_sql_comment", "true");
lemfb.setJpaPropertyMap(properties);
return lemfb;
}
@Bean(name = "tm")
public PlatformTransactionManager platformTransactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
}
|
✅ DataSourceProperties
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| package com.example.supercoding2stsohee.config.properties;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
@Getter
@Setter
@ConfigurationProperties(prefix = "datasource")
public class DataSourceProperties {
private String username;
private String password;
private String driverClassName;
private String url;
}
|
3. DTO
✅ SignUpRequest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| package com.example.supercoding2stsohee.web.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class SignUpRequest {
private String name;
private String phoneNumber;
private String nickName;
private String email;
private String password;
private String profileImg;
private String address;
private String gender;
}
|
✅ LoginRequest(DTO)
1
2
3
4
5
6
7
8
9
10
11
12
13
| import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class LoginRequest {
private String email;
private String password;
}
|
4. Entity
✅ User(Entity)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
| package com.example.supercoding2stsohee.repository.user;
import com.example.supercoding2stsohee.repository.userRoles.UserRoles;
import jakarta.persistence.*;
import lombok.*;
import java.time.LocalDateTime;
import java.util.List;
@Entity
@Getter
@Setter
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(of = "userId")
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_id")
private Integer userId;
@Column(name = "name", nullable = false)
private String name;
@Column(name = "phone_number", nullable = false)
private String phoneNumber;
@Column(name = "email", nullable = false)
private String email;
@Column(name = "nick_name", nullable = false)
private String nickName;
@Column(name = "password", nullable = false)
private String password;
@Column(name = "profile_img", nullable = false)
private String profileImg;
@Column(name = "address", nullable = false)
private String address;
@Column(name = "gender", nullable = false)
private String gender;
@Column(name = "status", nullable = false)
private String status;
@Column(name = "failure_count", nullable = false)
private Integer failureCount;
@Column(name = "create_at", nullable = false)
private LocalDateTime createdAt;
@Column(name = "delete_at")
private LocalDateTime deletedAt;
@Column(name = "lock_at")
private LocalDateTime lockedAt;
@OneToMany(mappedBy = "user", cascade = CascadeType.ALL, orphanRemoval = true) //cascade, orphanRemoval 추가해보았음
private List<UserRoles> userRoles;
}
|
✅ Roles(Entity)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| package com.example.supercoding2stsohee.repository.roles;
import jakarta.persistence.*;
import lombok.*;
@Entity
@Getter
@Setter
@EqualsAndHashCode(of = "roleId")
@Table(name = "roles")
public class Roles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "roles_id")
private Integer rolesId;
@Column(name = "name", nullable = false)
private String name;
}
|
✅ UserRole(Entity)
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
32
| package com.example.supercoding2stsohee.repository.userRoles;
import com.example.supercoding2stsohee.repository.roles.Roles;
import com.example.supercoding2stsohee.repository.user.User;
import jakarta.persistence.*;
import lombok.Getter;
import lombok.Setter;
@Entity
@Getter
@Setter
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Table(name = "user_roles")
public class UserRoles {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "user_roles_id")
private Integer userRolesId;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
@ManyToOne
@JoinColumn(name = "roles_id")
private Roles roles;
}
|
5. JPA
✅ UserJpa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
| package com.example.supercoding2stsohee.repository.user;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import java.util.Optional;
@Repository
public interface UserJpa extends JpaRepository<User, Integer> {
@Query(
"SELECT u " +
"FROM User u " +
"JOIN FETCH u.userRoles ur " +
"JOIN FETCH ur.roles r " +
"WHERE u.email = ?1 "
)
Optional<User> findByEmailFetchJoin(String email);
}
|
✅ RolesJpa
1
2
3
4
5
6
7
8
9
| package com.example.supercoding2stsohee.repository.roles;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface RolesJpa extends JpaRepository<Roles, Integer> {
}
|
✅ UserRolesJpa
1
2
3
4
5
6
7
8
9
| package com.example.supercoding2stsohee.repository.userRoles;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface UserRolesJpa extends JpaRepository<UserRoles, Integer> {
}
|
☑️ Security setting
6. CustomUserDetails
- CustomUserDetails implements UserDetails
💡 UserDetails
interface by JAVA security, encapsulated user info retrieved by Spring Security during the authentication process.
includes methods such as getUsername()
,
> getPassword()
,
> getAuthorities()
(권한조회),
> isEnabled()
,
> isAccountNonexpired()
,
> isAccountNonLocked()
,
> isCredentialNonExpired()
- 그래서 @Override 하면 된다.
- JWT token에 대한 정보 설정
- JWT token을 받을 형식
- 권한 조회
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
| package com.example.supercoding2stsohee.repository.userDetails;
import lombok.*;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class CustomUserDetails implements UserDetails {
@Getter
private Integer userId;
private String email;
private String password;
private List<String> authorities;
//권한
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
}
// email 과 password로 유저 인식
@Override
public String getPassword() {
return this.password;
}
@Override
public String getUsername() {
return this.email;
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
|
7. CustomUserDetailService setting
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
32
33
34
35
36
37
38
39
40
41
| package com.example.supercoding2stsohee.service.security;
import com.example.supercoding2stsohee.repository.roles.Roles;
import com.example.supercoding2stsohee.repository.user.User;
import com.example.supercoding2stsohee.repository.user.UserJpa;
import com.example.supercoding2stsohee.repository.userDetails.CustomUserDetails;
import com.example.supercoding2stsohee.repository.userRoles.UserRoles;
import com.example.supercoding2stsohee.service.exceptions.NullPointerException;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Primary;
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 java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
@Primary //이 bean이 default
public class CustomUserDetailService implements UserDetailsService {
private final UserJpa userJpa;
//email로 User 찾기
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
User user = userJpa.findByEmailFetchJoin(email)
.orElseThrow(()-> new NullPointerException("email에 해당하는 user를 찾을 수 없습니다."));
// 해당 user의 email 로 조회한 정보를 CustomUserDetails repository에 빌더로 넣어준다.
return CustomUserDetails.builder()
.userId(user.getUserId())
.email(user.getEmail())
.password(user.getPassword())
.authorities(user.getUserRoles().stream().map(UserRoles::getRoles).map(Roles::getName).collect(Collectors.toList()))
.build();
}
}
|
8. JwtTokenProvider
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
| package com.example.supercoding2stsohee.config.security;
import com.example.supercoding2stsohee.service.security.CustomUserDetailService;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import jakarta.annotation.PostConstruct;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;
import java.util.Base64;
import java.util.Date;
import java.util.List;
@Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final UserDetailsService userDetailsService;
@Value("${jwtpassword.source}")
private String secretKey;
private String key;
@PostConstruct
public void setUp(){ // JWT_SECRET_KEY를 인코딩
key= Base64.getEncoder().encodeToString(secretKey.getBytes());
}
private long tokenValidMillisecond= 1000L * 60 * 60; //Token이 유효한 시간 1시간
public String resolveToken(HttpServletRequest request) {
return request.getHeader("Token");
}
public String createToken(String email, List<String> roles){ // 토큰 생성
Claims claims= Jwts.claims().setSubject(email); //claim: piece of info about a subject(user/entity)
claims.put("roles", roles);
Date now= new Date();
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime() + tokenValidMillisecond))
.signWith(SignatureAlgorithm.HS256, key)
.compact();
}
public boolean validateToken(String jwtToken) {
try{
Claims claims= Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody(); //parse: jwt의 authenticity를 inspect하기 위해 정보를 extract하는 것
Date now= new Date();
return !claims.getExpiration().before(now); //9시까지 유효한데 지금이 8시 반이면 before이 아니니까 거짓! 따라서 참을 반환
//유효기간이 지금보다 전이면 안되지.
} catch(Exception e){
return false;
}
}
public Authentication getAuthentication(String jwtToken) {
UserDetails userDetails = userDetailsService.loadUserByUsername(getUserEmail(jwtToken));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
public String getUserEmail(String jwtToken){
return Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody().getSubject();
}
}
|
9. JwtAuthenticationFilter
JwtAuthenticationFilter extends OncePerRequestFilter
jwt가 있는지 확인하고 권한 주기
doFilterInternal()
: request, response, filterChain을 받아 JWT를 쪼개서
resolveToken()
: token에서 원하는 정보 가져오기- JWT가 Null이 아니고
validateToken()
토큰이 유효한지 검사 getAuthentication()
: JwtTokenProvider에서 권한 가져오기
SecurityContextHolder의 context에 권한 auth를 set 한다.
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
| package com.example.supercoding2stsohee.web.filters;
import com.example.supercoding2stsohee.config.security.JwtTokenProvider;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
@RequiredArgsConstructor
public class JwtAuthenticationFilter extends OncePerRequestFilter {
private final JwtTokenProvider jwtTokenProvider;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
String jwtToken= jwtTokenProvider.resolveToken(request); // Token 에서 원하는 정보를 가져오기
if(jwtToken != null && jwtTokenProvider.validateToken(jwtToken)){ // jwtToken 이 존재하고 유효하다면
Authentication auth= jwtTokenProvider.getAuthentication(jwtToken); // jwtTokenProvider 에서 권한을 가져오고
SecurityContextHolder.getContext().setAuthentication(auth); // SecurityContextHolder.getContext() 에 auth 를 넣어준다.
}
filterChain.doFilter(request, response);
}
}
|
☑️ SignController, AuthService, SecurityConfig, PasswordEncoderConfig
10. SignController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
| package com.example.supercoding2stsohee.web.controller;
import com.example.supercoding2stsohee.service.AuthService;
import com.example.supercoding2stsohee.web.dto.SignUpRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
public class SignController{
private final AuthService authService;
@PostMapping("/sign-up")
public String register(@RequestBody SignUpRequest signUpRequest){
boolean isSuccess= authService.signUp(signUpRequest);
return isSuccess ? "회원가입 성공" : "회원가입 실패";
}
}
|
ResponseDTO 받도록 정의
1
2
3
4
5
6
| @PostMapping("/sign-up")
public ResponseDto register(@RequestBody SignUpRequestDto signUpRequestDto){
boolean isSuccess= authService.signUp(signUpRequestDto);
if(isSuccess) return new ResponseDto(HttpStatus.OK.value(), "SignUp successful");
else return new ResponseDto(HttpStatus.BAD_REQUEST.value(), "SignUp fail");
}
|
11. AuthService
SignController 를 구현한 service가 AuthService
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
| package com.example.supercoding2stsohee.service;
import com.example.supercoding2stsohee.repository.roles.Roles;
import com.example.supercoding2stsohee.repository.roles.RolesJpa;
import com.example.supercoding2stsohee.repository.user.User;
import com.example.supercoding2stsohee.repository.userRoles.UserRoles;
import com.example.supercoding2stsohee.repository.userRoles.UserRolesJpa;
import com.example.supercoding2stsohee.repository.user.UserJpa;
import com.example.supercoding2stsohee.web.dto.SignUpRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
@Service
@RequiredArgsConstructor
public class AuthService {
private final RolesJpa rolesJpa;
private final UserRolesJpa userRolesJpa;
private final UserJpa userJpa;
private final PasswordEncoder passwordEncoder;
@Transactional(transactionManager = "tm")
public boolean signUp(SignUpRequest signUpRequest) {
if(userJpa.existsByEmail(signUpRequest.getEmail())){
return false;
}
Roles roles= rolesJpa.findByName("ROLE_USER");
User user= User.builder()
.name(signUpRequest.getName())
.phoneNumber(signUpRequest.getPhoneNumber())
.email(signUpRequest.getEmail())
.nickName(signUpRequest.getNickName())
.password(passwordEncoder.encode(signUpRequest.getPassword())) //passwordEncoder
.profileImg(signUpRequest.getProfileImg())
.address(signUpRequest.getAddress())
.gender(signUpRequest.getGender())
.status("normal")
.failureCount(0)
.createdAt(LocalDateTime.now())
.build();
userJpa.save(user);
userRolesJpa.save(
UserRoles.builder()
.user(user)
.roles(roles)
.build()
);
return true;
}
}
|
같은 아이디로 회원가입 시도하면 bad request exception
1
2
3
| if(userJpa.existsByMyId(signUpRequestDto.getMyId()))
throw new BadRequestException("There is already user with ID: "+ signUpRequestDto.getMyId());
|
(추가) UserJpa
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| @Repository
public interface UserJpa extends JpaRepository<User, Integer> {
@Query(
"SELECT u " +
"FROM User u " +
"JOIN FETCH u.userRoles ur " +
"JOIN FETCH ur.roles r " +
"WHERE u.email = ?1 "
)
Optional<User> findByEmailFetchJoin(String email);
boolean existsByEmail(String email);
}
|
(추가) RolesJpa
1
2
3
4
| @Repository
public interface RolesJpa extends JpaRepository<Roles, Integer> {
Roles findByName(String roleUser);
}
|
12. PasswordEncoder
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| package com.example.supercoding2stsohee.config.security;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class PasswordEncoderConfig {
@Bean
public PasswordEncoder passwordEncoder(){
return new BCryptPasswordEncoder();
}
}
|
13. SecurityConfig
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
| package com.example.supercoding2stsohee.config.security;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.headers(h -> h.frameOptions(f -> f.sameOrigin()))
.csrf(c->c.disable())
.httpBasic(h->h.disable())
.formLogin(f->f.disable())
.rememberMe(r->r.disable())
.sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
return http.build();
}
}
|
🔑 Login 로직 추가
(추가) SignController
1
2
3
4
5
6
| @PostMapping("/login")
public String login(@RequestBody LoginRequest loginRequest, HttpServletResponse httpServletResponse){
String token= authService.login(loginRequest);
httpServletResponse.setHeader("Token", token);
return "로그인 성공";
}
|
ResponseDTO 받도록 정의
1
2
3
4
5
6
| @PostMapping("/login")
public ResponseDto login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse httpServletResponse){
String token= authService.login(loginRequestDto);
httpServletResponse.setHeader("Token", token);
return new ResponseDto(HttpStatus.OK.value(), "Login Success");
}
|
(추가) AuthService(loginService 추가)
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
두 bean도 추가해주어야 한다.
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
| package com.example.supercoding2stsohee.service;
import com.example.supercoding2stsohee.config.security.JwtTokenProvider;
import com.example.supercoding2stsohee.repository.roles.Roles;
import com.example.supercoding2stsohee.repository.roles.RolesJpa;
import com.example.supercoding2stsohee.repository.user.User;
import com.example.supercoding2stsohee.repository.userRoles.UserRoles;
import com.example.supercoding2stsohee.repository.userRoles.UserRolesJpa;
import com.example.supercoding2stsohee.repository.user.UserJpa;
import com.example.supercoding2stsohee.service.exceptions.NullPointerException;
import com.example.supercoding2stsohee.web.dto.LoginRequest;
import com.example.supercoding2stsohee.web.dto.SignUpRequest;
import lombok.RequiredArgsConstructor;
import org.springframework.security.authentication.AuthenticationManager; //securityConfig에 bean추가
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.server.NotAcceptableStatusException;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
@Service
@RequiredArgsConstructor
public class AuthService {
private final RolesJpa rolesJpa;
private final UserRolesJpa userRolesJpa;
private final UserJpa userJpa;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
@Transactional(transactionManager = "tm")
public boolean signUp(SignUpRequest signUpRequest) {
if(userJpa.existsByEmail(signUpRequest.getEmail())){
return false;
}
Roles roles= rolesJpa.findByName("ROLE_USER");
User user= User.builder()
.name(signUpRequest.getName())
.phoneNumber(signUpRequest.getPhoneNumber())
.email(signUpRequest.getEmail())
.nickName(signUpRequest.getNickName())
.password(passwordEncoder.encode(signUpRequest.getPassword())) //passwordEncoder
.profileImg(signUpRequest.getProfileImg())
.address(signUpRequest.getAddress())
.gender(signUpRequest.getGender())
.status("normal")
.failureCount(0)
.createdAt(LocalDateTime.now())
.build();
userJpa.save(user);
userRolesJpa.save(
UserRoles.builder()
.user(user)
.roles(roles)
.build()
);
return true;
}
public String login(LoginRequest loginRequest) {
try{
Authentication authentication= authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequest.getEmail(), loginRequest.getPassword())
);
SecurityContextHolder.getContext().setAuthentication(authentication);
User user= userJpa.findByEmailFetchJoin(loginRequest.getEmail())
.orElseThrow(()-> new NullPointerException("해당 이메일로 계정을 찾을 수 없습니다.")); //NotFoundException도 가능
List<String> roles= user.getUserRoles().stream().map(UserRoles::getRoles).map(Roles::getName).collect(Collectors.toList());
return jwtTokenProvider.createToken(loginRequest.getEmail(), roles);
}catch(Exception e){
e.printStackTrace();
throw new NotAcceptableStatusException("로그인 할 수 없습니다.");
}
}
}
|
13. SecurityConfig 추가
authenticationManager 추가
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
32
33
34
35
36
37
38
39
40
41
42
| package com.example.supercoding2stsohee.config.security;
import com.example.supercoding2stsohee.web.filters.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.headers(h -> h.frameOptions(f -> f.sameOrigin()))
.csrf(c->c.disable())
.httpBasic(h->h.disable())
.formLogin(f->f.disable())
.rememberMe(r->r.disable())
.sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception{
return authenticationConfiguration.getAuthenticationManager();
}
}
|
☑️ 권한 설정
(추가) SecurityConfig(authorizeRequests
추가)
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
| package com.example.supercoding2stsohee.config.security;
import com.example.supercoding2stsohee.web.filters.JwtAuthenticationFilter;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
private final JwtTokenProvider jwtTokenProvider;
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.headers(h -> h.frameOptions(f -> f.sameOrigin()))
.csrf(c->c.disable())
.httpBasic(h->h.disable())
.formLogin(f->f.disable())
.rememberMe(r->r.disable())
.sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeRequests(a -> //authorizeHTTPRequests 하면 안 됨!! 그러면 requestMatchers를 못 받음
a
.requestMatchers("/resources/static/**", "/sign-up", "/login").permitAll() // 로그인 안해도 가능
.requestMatchers("/test").hasRole("USER") // user 권한이 있어야 가능
// DB ROLE 테이블에는 ROLE_USER이라고 되어있지만 여기서 USER만 넣어도 앞에 `ROLE_`이 자동으로 붙음
)
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception{
return authenticationConfiguration.getAuthenticationManager();
}
}
|
☑️ Token 관련 excpetion 설정
- CustomAccessDeniedHandler
- CustomAuthenticationEntryPoint
- ExcpetionController
- (추가) SecurityConfig의 SecurityFilterChain에 exceptionHandling 추가
✅ CustomAccessDeniedHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| package com.example.supercoding2stsohee.service.exceptions;
import jakarta.persistence.Access;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Slf4j
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.sendRedirect("/exceptions/access-denied");
}
}
|
✅ CustomAuthenticationEntryPoint
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
| package com.example.supercoding2stsohee.service.exceptions;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import java.io.IOException;
@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
response.sendRedirect("/exceptions/entrypoint");
}
}
|
✅ ExcpetionController
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
| package com.example.supercoding2stsohee.web.controller;
import com.example.supercoding2stsohee.service.exceptions.NullPointerException;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequiredArgsConstructor
@RequestMapping(value="/exceptions")
public class ExceptionController {
@GetMapping(value= "/entrypoint")
public void entryPointException(){
throw new NullPointerException("로그인이 필요합니다");
}
@GetMapping(value="/access-denied")
public void accessDeniedException(){
throw new NullPointerException("권한이 없습니다.");
}
}
|
✅ (추가) SecurityConfig의 SecurityFilterChain에 exceptionHandling 추가
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
http
.headers(h -> h.frameOptions(f -> f.sameOrigin()))
.csrf(c->c.disable())
.httpBasic(h->h.disable())
.formLogin(f->f.disable())
.rememberMe(r->r.disable())
.sessionManagement(s->s.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authorizeRequests(a ->
a
.requestMatchers("/resources/static/**", "/sign-up", "/login").permitAll() // 로그인 안해도 가능
.requestMatchers("/test").hasRole("USER") // user 권한이 있어야 가능
// DB ROLE 테이블에는 ROLE_USER이라고 되어있지만 여기서 USER만 넣어도 앞에 `ROLE_`이 자동으로 붙음
)
.exceptionHandling(e->{
e.authenticationEntryPoint(new CustomAuthenticationEntryPoint());
e.accessDeniedHandler(new CustomAccessDeniedHandler());
})
.addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider), UsernamePasswordAuthenticationFilter.class);
return http.build();
}
|
☑️ TEST 코드에서 CustomerMemberDetails 사용
- TestController
- POSTMAN 으로 로그인 후 Token을 TEST 코드에 넣어주면
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
| package com.example.supercoding2stsohee.web.controller;
import com.example.supercoding2stsohee.repository.cart.CartJpa;
import com.example.supercoding2stsohee.repository.orderItem.OrderItemJpa;
import com.example.supercoding2stsohee.repository.orderTable.OrderTableJpa;
import com.example.supercoding2stsohee.repository.product.ProductJpa;
import com.example.supercoding2stsohee.repository.productOption.ProductOptionJpa;
import com.example.supercoding2stsohee.repository.productPhoto.ProductPhotoJpa;
import com.example.supercoding2stsohee.repository.review.ReviewJpa;
import com.example.supercoding2stsohee.repository.roles.RolesJpa;
import com.example.supercoding2stsohee.repository.userDetails.CustomUserDetails;
import com.example.supercoding2stsohee.repository.userRoles.UserRolesJpa;
import com.example.supercoding2stsohee.repository.user.User;
import com.example.supercoding2stsohee.repository.user.UserJpa;
import lombok.RequiredArgsConstructor;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.webjars.NotFoundException;
@RestController
@RequiredArgsConstructor
public class test {
private final UserJpa userJpa;
private final RolesJpa rolesJpa;
private final UserRolesJpa userRolesJpa;
private final ProductJpa productJpa;
private final ProductOptionJpa productOptionJpa;
private final ProductPhotoJpa productPhotoJpa;
private final ReviewJpa reviewJpa;
private final CartJpa cartJpa;
private final OrderTableJpa orderTableJpa;
private final OrderItemJpa orderItemJpa;
@GetMapping("/test")
public String test() {
User user = userJpa.findById(1).orElseThrow(() -> new NotFoundException("ss"));
Integer userId = user.getUserId();
return "test success: " + userId;
}
@GetMapping("/test2")
public String test2(@AuthenticationPrincipal CustomUserDetails customUserDetails) {
return "test success, userId: " + customUserDetails.getUserId();
}
}
|
☑️ Logout
✅ JWT Token provider
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| @Component
@RequiredArgsConstructor
public class JwtTokenProvider {
private final UserDetailsService userDetailsService;
@Value("${JWT_SECRET_KEY}")
private String secretKey;
private String key;
@PostConstruct
public void setUp(){
key= Base64.getEncoder().encodeToString(secretKey.getBytes());
}
private long tokenValidMillisecond= 1000L * 60 * 60;
public String resolveToken(HttpServletRequest request){
return request.getHeader("Token");
}
public String createToken(String myId, List<String> role){
Claims claims= Jwts.claims().setSubject(myId);
claims.put("role", role);
Date now= new Date();
return Jwts.builder()
.setClaims(claims)
.setIssuedAt(now)
.setExpiration(new Date(now.getTime()+ tokenValidMillisecond))
.signWith(SignatureAlgorithm.HS256, key)
.compact();
}
public boolean validateToken(String jwtToken){
try{
Claims claims= Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody();
Date now= new Date();
return !claims.getExpiration().before(now);
} catch(Exception e){
return false;
}
}
public Authentication getAuthentication(String jwtToken){
UserDetails userDetails = userDetailsService.loadUserByUsername(getUserMyId(jwtToken));
return new UsernamePasswordAuthenticationToken(userDetails, "", userDetails.getAuthorities());
}
public String getUserMyId(String jwtToken) {
return Jwts.parser().setSigningKey(key).parseClaimsJws(jwtToken).getBody().getSubject();
}
//logout
private Set<String> tokenBlackList = new HashSet<>();
public void addToBlackList(String currentToken) {
System.out.println("Token added to blacklist: " + currentToken);
tokenBlackList.add(currentToken);
}
public boolean isTokenBlackListed(String jwtToken){
return tokenBlackList.contains(jwtToken);
}
}
|
✅ SignController
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
| @RestController
@RequiredArgsConstructor
@RequestMapping(value="/auth")
public class SignController {
private final AuthService authService;
@PostMapping("/sign-up")
public ResponseDto register(@RequestBody SignUpRequestDto signUpRequestDto){
boolean isSuccess= authService.signUp(signUpRequestDto);
if(isSuccess) return new ResponseDto(HttpStatus.OK.value(), "SignUp successful");
else return new ResponseDto(HttpStatus.BAD_REQUEST.value(), "SignUp fail");
}
@PostMapping("/login")
public ResponseDto login(@RequestBody LoginRequestDto loginRequestDto, HttpServletResponse httpServletResponse){
String token= authService.login(loginRequestDto);
httpServletResponse.setHeader("Token", token);
return new ResponseDto(HttpStatus.OK.value(), "Login Success");
}
@PostMapping("/logout")
public ResponseDto logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse){
boolean isSuccess= authService.logout(httpServletRequest, httpServletResponse);
if(isSuccess) return new ResponseDto(HttpStatus.OK.value(), "Logout successful" );
else return new ResponseDto(HttpStatus.BAD_REQUEST.value(), "Logout fail");
}
}
|
✅ AuthService
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
| @Service
@RequiredArgsConstructor
public class AuthService {
private final RoleJpa roleJpa;
private final UserRoleJpa userRoleJpa;
private final UserJpa userJpa;
private final PasswordEncoder passwordEncoder;
private final AuthenticationManager authenticationManager;
private final JwtTokenProvider jwtTokenProvider;
public boolean signUp(SignUpRequestDto signUpRequestDto) {
if(userJpa.existsByMyId(signUpRequestDto.getMyId()))
throw new BadRequestException("There is already user with ID: "+ signUpRequestDto.getMyId());
Role role= roleJpa.findByName("ROLE_USER");
User user= User.builder()
.name(signUpRequestDto.getName())
.myId(signUpRequestDto.getMyId())
.password(passwordEncoder.encode(signUpRequestDto.getPassword()))
.birthday(signUpRequestDto.getBirthday())
.phoneNumber(signUpRequestDto.getPhoneNumber())
.build();
userJpa.save(user);
userRoleJpa.save(
UserRole.builder()
.user(user)
.role(role)
.build()
);
return true;
}
public String login(LoginRequestDto loginRequestDto) {
try{
Authentication authentication= authenticationManager.authenticate(
new UsernamePasswordAuthenticationToken(loginRequestDto.getMyId(), loginRequestDto.getPassword())
);
SecurityContextHolder.getContext().setAuthentication(authentication);
User user= userJpa.findByMyIdFetchJoin(loginRequestDto.getMyId())
.orElseThrow(()-> new NotFoundException("Cannot find user with ID"));
List<String> role= user.getUserRoleList().stream().map(UserRole::getRole).map(Role::getName).collect(Collectors.toList());
return jwtTokenProvider.createToken(loginRequestDto.getMyId(), role);
}catch(Exception e){
e.printStackTrace();
throw new NotAcceptableStatusException("Login not possible");
}
}
public boolean logout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) {
Authentication auth= SecurityContextHolder.getContext().getAuthentication();
if(auth != null){
String currentToken= jwtTokenProvider.resolveToken(httpServletRequest);
jwtTokenProvider.addToBlackList(currentToken);
new SecurityContextLogoutHandler().logout(httpServletRequest, httpServletResponse, auth);
}
return true;
}
}
|