-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #12 from PawWithU/feat/11-Auth
[Feature] JWT, Redis 기본 설정
- Loading branch information
Showing
19 changed files
with
742 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
src/main/java/com/pawwithu/connectdog/config/RedisConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
package com.pawwithu.connectdog.config; | ||
|
||
|
||
import jakarta.annotation.PostConstruct; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.beans.factory.annotation.Value; | ||
import org.springframework.cache.annotation.CachingConfigurerSupport; | ||
import org.springframework.context.annotation.Bean; | ||
import org.springframework.context.annotation.Configuration; | ||
import org.springframework.data.redis.cache.RedisCacheConfiguration; | ||
import org.springframework.data.redis.cache.RedisCacheManager; | ||
import org.springframework.data.redis.connection.RedisConnectionFactory; | ||
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory; | ||
import org.springframework.data.redis.core.RedisTemplate; | ||
import org.springframework.data.redis.repository.configuration.EnableRedisRepositories; | ||
import org.springframework.data.redis.serializer.*; | ||
|
||
import java.time.Duration; | ||
|
||
@Slf4j | ||
@Configuration | ||
@EnableRedisRepositories | ||
public class RedisConfig extends CachingConfigurerSupport { | ||
@Value("${spring.data.redis.port}") | ||
private int port; | ||
|
||
@Value("${spring.data.redis.host}") | ||
private String host; | ||
|
||
@PostConstruct // 해당 메서드는 객체의 모든 의존성이 주입된 직후에 자동으로 호출 | ||
public void printValues() { | ||
log.info("Redis Host: " + host); | ||
log.info("Redis Port: " + port); | ||
} | ||
|
||
|
||
@Bean | ||
public RedisConnectionFactory redisConnectionFactory() { | ||
return new LettuceConnectionFactory(host, port); | ||
} | ||
|
||
@Bean(name = "redisTemplate") | ||
public RedisTemplate<Long, String> redisTemplate(RedisConnectionFactory redisConnectionFactory) { | ||
RedisTemplate<Long, String> redisTemplate = new RedisTemplate<>(); | ||
|
||
redisTemplate.setConnectionFactory(redisConnectionFactory); | ||
redisTemplate.setKeySerializer(new GenericToStringSerializer<Long>(Long.class)); // Long 타입에 대한 직렬화 도구로 GenericToStringSerializer 사용 | ||
redisTemplate.setValueSerializer(new StringRedisSerializer()); | ||
|
||
return redisTemplate; | ||
} | ||
|
||
@Bean(name = "redisBlackListTemplate") | ||
public RedisTemplate<String, String> redisBlackListTemplate(RedisConnectionFactory redisConnectionFactory) { | ||
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>(); | ||
|
||
redisTemplate.setConnectionFactory(redisConnectionFactory); | ||
redisTemplate.setKeySerializer(new StringRedisSerializer()); | ||
redisTemplate.setValueSerializer(new StringRedisSerializer()); | ||
|
||
return redisTemplate; | ||
} | ||
|
||
// Redis Cache 적용을 위한 RedisCacheManager 설정 | ||
@Bean | ||
public RedisCacheManager redisCacheManager(RedisConnectionFactory redisConnectionFactory) { | ||
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig() | ||
.serializeKeysWith(RedisSerializationContext | ||
.SerializationPair.fromSerializer(new StringRedisSerializer())) // StringRedisSerializer: binary 데이터로 저장되기 때문에 이를 String 으로 변환 | ||
.serializeValuesWith(RedisSerializationContext | ||
.SerializationPair.fromSerializer(new GenericJackson2JsonRedisSerializer())) | ||
.entryTtl(Duration.ofDays(14).plusHours(2)); // TTL 2주 + 2시간으로 설정 | ||
|
||
return RedisCacheManager | ||
.RedisCacheManagerBuilder | ||
.fromConnectionFactory(redisConnectionFactory) | ||
.cacheDefaults(redisCacheConfiguration) | ||
.build(); | ||
} | ||
|
||
} |
59 changes: 59 additions & 0 deletions
59
src/main/java/com/pawwithu/connectdog/config/SecurityConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package com.pawwithu.connectdog.config; | ||
|
||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
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.crypto.factory.PasswordEncoderFactories; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.security.web.SecurityFilterChain; | ||
import org.springframework.security.web.authentication.logout.LogoutFilter; | ||
import org.springframework.security.web.servlet.util.matcher.MvcRequestMatcher; | ||
import org.springframework.web.servlet.handler.HandlerMappingIntrospector; | ||
|
||
import static org.springframework.security.config.Customizer.withDefaults; | ||
|
||
@Slf4j | ||
@Configuration | ||
@EnableWebSecurity | ||
@RequiredArgsConstructor | ||
public class SecurityConfig { | ||
|
||
|
||
@Bean | ||
public SecurityFilterChain filterChain(HttpSecurity http, HandlerMappingIntrospector introspector) throws Exception { | ||
MvcRequestMatcher.Builder mvcMatcherBuilder = new MvcRequestMatcher.Builder(introspector); | ||
http | ||
.formLogin(formLogin -> formLogin.disable()) | ||
.httpBasic(httpBasic -> httpBasic.disable()) | ||
.csrf(csrf -> csrf.disable()) | ||
.cors(withDefaults()) | ||
.headers(headers -> headers.frameOptions(frameOptions -> frameOptions.disable())) | ||
.sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)) | ||
.authorizeHttpRequests(request -> | ||
request.requestMatchers(mvcMatcherBuilder.pattern("/login")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/api/sign-up")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/h2-console/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/css/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/js/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/images/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/error")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/favicon.ico")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/swagger-ui/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/swagger-resources/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/v3/api-docs/**")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/api/sign-up/email")).permitAll() | ||
.requestMatchers(mvcMatcherBuilder.pattern("/api/members/userName/isDuplicated")).permitAll() | ||
.anyRequest().authenticated()); | ||
|
||
return http.build(); | ||
} | ||
|
||
@Bean | ||
public PasswordEncoder passwordEncoder() { | ||
return PasswordEncoderFactories.createDelegatingPasswordEncoder(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/main/java/com/pawwithu/connectdog/domain/auth/controller/SignUpController.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.pawwithu.connectdog.domain.auth.controller; | ||
|
||
import com.pawwithu.connectdog.domain.auth.dto.request.SignUpRequest; | ||
import com.pawwithu.connectdog.domain.auth.service.AuthService; | ||
import com.pawwithu.connectdog.error.dto.ErrorResponse; | ||
import io.swagger.v3.oas.annotations.Operation; | ||
import io.swagger.v3.oas.annotations.media.Content; | ||
import io.swagger.v3.oas.annotations.media.Schema; | ||
import io.swagger.v3.oas.annotations.responses.ApiResponse; | ||
import io.swagger.v3.oas.annotations.tags.Tag; | ||
import lombok.RequiredArgsConstructor; | ||
import org.springframework.http.HttpStatus; | ||
import org.springframework.http.ResponseEntity; | ||
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; | ||
|
||
@Tag(name = "Sign-Up", description = "Sign-Up API") | ||
@RestController | ||
@RequiredArgsConstructor | ||
@RequestMapping("/api/sign-up") | ||
public class SignUpController { | ||
|
||
private final AuthService authService; | ||
|
||
@Operation(summary = "자체 회원가입", description = "이메일을 사용해 회원가입을 합니다.", | ||
responses = {@ApiResponse(responseCode = "204", description = "자체 회원가입 성공") | ||
, @ApiResponse(responseCode = "400" | ||
, description = "1. 이미 존재하는 이메일입니다. \t\n 2. 이미 존재하는 사용자 닉네임입니다." | ||
, content = @Content(schema = @Schema(implementation = ErrorResponse.class))) | ||
}) | ||
@PostMapping | ||
public ResponseEntity<Void> signUp(@RequestBody SignUpRequest signUpRequest) { | ||
authService.signUp(signUpRequest); | ||
return ResponseEntity.noContent().build(); | ||
} | ||
|
||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/pawwithu/connectdog/domain/auth/dto/request/SignUpRequest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.pawwithu.connectdog.domain.auth.dto.request; | ||
|
||
import com.pawwithu.connectdog.domain.member.entity.Member; | ||
import com.pawwithu.connectdog.domain.member.entity.Role; | ||
|
||
public record SignUpRequest( | ||
String email, String password, String nickname, | ||
String name, String phone, | ||
String url, | ||
Boolean isOptionAgr, | ||
Role role | ||
) { | ||
public Member toEntity() { | ||
return Member.builder() | ||
.email(email) | ||
.password(password) | ||
.nickname(nickname) | ||
.name(name) | ||
.phone(phone) | ||
.url(url) | ||
.isOptionAgr(isOptionAgr) | ||
.role(role) | ||
.build(); | ||
} | ||
} |
39 changes: 39 additions & 0 deletions
39
src/main/java/com/pawwithu/connectdog/domain/auth/service/AuthService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
package com.pawwithu.connectdog.domain.auth.service; | ||
|
||
import com.pawwithu.connectdog.domain.auth.dto.request.SignUpRequest; | ||
import com.pawwithu.connectdog.domain.member.entity.Member; | ||
import com.pawwithu.connectdog.domain.member.repository.MemberRepository; | ||
import com.pawwithu.connectdog.error.exception.custom.BadRequestException; | ||
import lombok.RequiredArgsConstructor; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
import org.springframework.stereotype.Service; | ||
import org.springframework.transaction.annotation.Transactional; | ||
|
||
import static com.pawwithu.connectdog.error.ErrorCode.ALREADY_EXIST_EMAIL; | ||
import static com.pawwithu.connectdog.error.ErrorCode.ALREADY_EXIST_NICKNAME; | ||
|
||
@Slf4j | ||
@Service | ||
@Transactional | ||
@RequiredArgsConstructor | ||
public class AuthService { | ||
|
||
private final MemberRepository memberRepository; | ||
private final PasswordEncoder passwordEncoder; | ||
|
||
public void signUp(SignUpRequest signUpRequest) { | ||
|
||
if (memberRepository.existsByEmail(signUpRequest.email())) { | ||
throw new BadRequestException(ALREADY_EXIST_EMAIL); | ||
} | ||
if (memberRepository.existsByNickname(signUpRequest.nickname())) { | ||
throw new BadRequestException(ALREADY_EXIST_NICKNAME); | ||
} | ||
|
||
Member member = signUpRequest.toEntity(); | ||
member.passwordEncode(passwordEncoder); | ||
memberRepository.save(member); | ||
} | ||
|
||
} |
53 changes: 53 additions & 0 deletions
53
src/main/java/com/pawwithu/connectdog/domain/member/entity/Member.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package com.pawwithu.connectdog.domain.member.entity; | ||
|
||
import jakarta.persistence.*; | ||
import lombok.*; | ||
import org.springframework.security.crypto.password.PasswordEncoder; | ||
|
||
@Getter | ||
@NoArgsConstructor(access = AccessLevel.PROTECTED) | ||
@AllArgsConstructor | ||
@Entity | ||
public class Member { | ||
|
||
@Id | ||
@GeneratedValue(strategy = GenerationType.IDENTITY) | ||
private Long id; | ||
|
||
private String email; // 이메일 | ||
private String password; // 비밀번호 | ||
private String nickname; // 닉네임 | ||
private String name; // 이름 | ||
private String phone; // 이동봉사자 휴대폰 번호 | ||
private String url; // 이동봉사 단체 링크 | ||
private Boolean isOptionAgr; // 선택 이용약관 체크 여부 | ||
|
||
@Enumerated(EnumType.STRING) | ||
private Role role; | ||
|
||
@Enumerated(EnumType.STRING) | ||
private SocialType socialType; // KAKAO, NAVER | ||
|
||
private String socialId; // 로그인한 소셜 타입 식별자 값 (일반 로그인의 경우 null) | ||
|
||
@Builder | ||
public Member(String email, String password, String nickname, String name, String phone, String url, Boolean isOptionAgr, Role role, SocialType socialType, String socialId) { | ||
this.email = email; | ||
this.password = password; | ||
this.nickname = nickname; | ||
this.name = name; | ||
this.phone = phone; | ||
this.url = url; | ||
this.isOptionAgr = isOptionAgr; | ||
this.role = role; | ||
this.socialType = socialType; | ||
this.socialId = socialId; | ||
} | ||
|
||
public void passwordEncode(PasswordEncoder passwordEncoder) { | ||
this.password = passwordEncoder.encode(this.password); | ||
} | ||
|
||
|
||
|
||
} |
15 changes: 15 additions & 0 deletions
15
src/main/java/com/pawwithu/connectdog/domain/member/entity/Role.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package com.pawwithu.connectdog.domain.member.entity; | ||
|
||
import lombok.Getter; | ||
import lombok.RequiredArgsConstructor; | ||
|
||
@Getter | ||
@RequiredArgsConstructor | ||
public enum Role { | ||
|
||
// 첫 로그인, 테스트 여부 구분 | ||
GUEST("ROLE_GUEST"), USER("ROLE_USER"), ADMIN("ROLE_ADMIN"); | ||
|
||
private final String key; | ||
|
||
} |
5 changes: 5 additions & 0 deletions
5
src/main/java/com/pawwithu/connectdog/domain/member/entity/SocialType.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
package com.pawwithu.connectdog.domain.member.entity; | ||
|
||
public enum SocialType { | ||
KAKAO, NAVER | ||
} |
20 changes: 20 additions & 0 deletions
20
src/main/java/com/pawwithu/connectdog/domain/member/repository/MemberRepository.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package com.pawwithu.connectdog.domain.member.repository; | ||
|
||
import com.pawwithu.connectdog.domain.member.entity.Member; | ||
import com.pawwithu.connectdog.domain.member.entity.SocialType; | ||
import org.springframework.data.jpa.repository.JpaRepository; | ||
|
||
import java.util.Optional; | ||
|
||
public interface MemberRepository extends JpaRepository<Member, Long> { | ||
|
||
Optional<Member> findByEmail(String email); | ||
Optional<Member> findByNickname(String nickname); | ||
|
||
// 소셜 타입과 소셜의 식별값으로 회원 찾는 메소드 -> 추가 정보를 입력받아 회원가입 진행 시 이용 | ||
Optional<Member> findBySocialTypeAndSocialId(SocialType socialType, String socialId); | ||
|
||
Boolean existsByEmail(String email); | ||
Boolean existsByNickname(String nickname); | ||
|
||
} |
Oops, something went wrong.