Skip to content
This repository was archived by the owner on Nov 21, 2023. It is now read-only.

Commit 6c7f49b

Browse files
committed
[#28] security 적용 (SecurityConfig.kt) , api mock 생성
1 parent 6219617 commit 6c7f49b

File tree

12 files changed

+218
-0
lines changed

12 files changed

+218
-0
lines changed

build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ project(":user-api") {
6262
implementation("io.springfox:springfox-boot-starter:3.0.0")
6363
implementation("org.springframework.boot:spring-boot-starter-security")
6464
implementation("org.springframework.security:spring-security-test")
65+
implementation("org.springframework.boot:spring-boot-starter-mail")
66+
implementation("org.springframework.boot:spring-boot-starter-security")
6567
runtimeOnly("com.h2database:h2")
6668
runtimeOnly("mysql:mysql-connector-java")
6769
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package com.sns.user.core.config
2+
3+
import com.sns.user.core.supports.securities.authentications.LoginUserService
4+
import com.sns.user.core.supports.securities.authentications.Role
5+
import org.springframework.context.annotation.Bean
6+
import org.springframework.context.annotation.Configuration
7+
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder
8+
import org.springframework.security.config.annotation.web.builders.HttpSecurity
9+
import org.springframework.security.config.annotation.web.builders.WebSecurity
10+
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
11+
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
12+
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder
13+
import org.springframework.security.crypto.password.PasswordEncoder
14+
15+
@Configuration
16+
@EnableWebSecurity
17+
class SecurityConfig(
18+
private val loginUserService: LoginUserService
19+
) : WebSecurityConfigurerAdapter() {
20+
override fun configure(auth: AuthenticationManagerBuilder?) {
21+
auth?.userDetailsService(loginUserService)
22+
?.passwordEncoder(passwordEncoder())
23+
}
24+
25+
override fun configure(http: HttpSecurity?) {
26+
if (http == null) return
27+
http.httpBasic().and().authorizeRequests()
28+
.antMatchers("/").permitAll()
29+
.antMatchers("/admin-api").hasRole(Role.ADMIN.name)
30+
.anyRequest().authenticated()
31+
.and().logout().logoutSuccessUrl("/").invalidateHttpSession(true).permitAll()
32+
.and().formLogin().loginPage("/sign-in")
33+
.and().csrf().disable()
34+
}
35+
36+
override fun configure(web: WebSecurity?) {
37+
super.configure(web)
38+
}
39+
40+
@Bean
41+
fun passwordEncoder(): PasswordEncoder? {
42+
return BCryptPasswordEncoder()
43+
}
44+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.sns.user.core.supports.securities.authentications
2+
3+
import org.springframework.security.access.annotation.Secured
4+
5+
// Role.USER.role
6+
@Secured("ROLE_USER")
7+
@Target(AnnotationTarget.FUNCTION)
8+
@Retention(AnnotationRetention.RUNTIME)
9+
annotation class IsLoginUser()
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.sns.user.core.supports.securities.authentications
2+
3+
import com.sns.user.component.user.domains.User
4+
import org.springframework.security.core.GrantedAuthority
5+
import org.springframework.security.core.userdetails.UserDetails
6+
7+
class LoginUser(val user: User) : UserDetails {
8+
override fun getAuthorities(): MutableCollection<out GrantedAuthority> = mutableListOf<GrantedAuthority>(Role.USER.createSimpleGrantedAuthority())
9+
override fun getUsername(): String = user.name
10+
override fun getPassword(): String = user.password
11+
override fun isAccountNonExpired(): Boolean = true
12+
override fun isAccountNonLocked(): Boolean = true
13+
override fun isCredentialsNonExpired(): Boolean = true
14+
override fun isEnabled(): Boolean = true
15+
16+
companion object {
17+
fun create(user: User?): UserDetails =
18+
if (user == null) InvalidUser() else LoginUser(user)
19+
}
20+
}
21+
22+
class InvalidUser : UserDetails {
23+
override fun getAuthorities(): MutableCollection<out GrantedAuthority> = mutableListOf()
24+
override fun getUsername(): String = ""
25+
override fun getPassword(): String = ""
26+
override fun isAccountNonExpired(): Boolean = false
27+
override fun isAccountNonLocked(): Boolean = false
28+
override fun isCredentialsNonExpired(): Boolean = false
29+
override fun isEnabled(): Boolean = false
30+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.sns.user.core.supports.securities.authentications
2+
3+
import com.sns.user.component.user.repositories.UserCrudRepository
4+
import org.springframework.security.core.userdetails.UserDetails
5+
import org.springframework.security.core.userdetails.UserDetailsService
6+
import org.springframework.stereotype.Service
7+
8+
@Service
9+
class LoginUserService(
10+
private val userCrudRepository: UserCrudRepository
11+
) : UserDetailsService {
12+
override fun loadUserByUsername(username: String?): UserDetails {
13+
if (username.isNullOrEmpty()) return InvalidUser()
14+
return LoginUser.create(userCrudRepository.findById(username).orElse(null))
15+
}
16+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package com.sns.user.core.supports.securities.authentications
2+
3+
import org.springframework.security.core.authority.SimpleGrantedAuthority
4+
5+
enum class Role(val role: String) {
6+
USER("ROLE_USER"),
7+
ADMIN("ROLE_ADMIN");
8+
9+
fun createSimpleGrantedAuthority(): SimpleGrantedAuthority = SimpleGrantedAuthority(this.role)
10+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.sns.user.endpoints.user
2+
3+
import org.springframework.web.bind.annotation.RequestMapping
4+
import org.springframework.web.bind.annotation.RestController
5+
6+
@RestController
7+
@RequestMapping("/api")
8+
class SignInController {
9+
10+
fun signIn() {
11+
}
12+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
package com.sns.user.endpoints.user
2+
3+
import org.springframework.web.bind.annotation.PostMapping
4+
import org.springframework.web.bind.annotation.RequestMapping
5+
import org.springframework.web.bind.annotation.RestController
6+
7+
@RestController
8+
@RequestMapping("/api")
9+
class SignOutController {
10+
11+
@PostMapping("/v1/sign-out")
12+
fun signOut() {
13+
// TODO 탈퇴
14+
}
15+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
package com.sns.user.endpoints.user
2+
3+
import com.sns.user.endpoints.user.requests.SignUpRequest
4+
import com.sns.user.endpoints.user.responses.IdExistsCheckResponse
5+
import javax.validation.constraints.Email
6+
import org.springframework.http.HttpStatus
7+
import org.springframework.validation.annotation.Validated
8+
import org.springframework.web.bind.annotation.GetMapping
9+
import org.springframework.web.bind.annotation.PathVariable
10+
import org.springframework.web.bind.annotation.PostMapping
11+
import org.springframework.web.bind.annotation.PutMapping
12+
import org.springframework.web.bind.annotation.RequestBody
13+
import org.springframework.web.bind.annotation.RequestMapping
14+
import org.springframework.web.bind.annotation.ResponseStatus
15+
import org.springframework.web.bind.annotation.RestController
16+
17+
@Validated
18+
@RestController
19+
@RequestMapping("/api")
20+
class SignUpController {
21+
22+
@ResponseStatus(HttpStatus.CREATED)
23+
@PostMapping("/v1/sign-up")
24+
fun signUp(@RequestBody request: SignUpRequest) {
25+
// TODO 패스워드 유효성 검증
26+
}
27+
28+
@ResponseStatus(HttpStatus.OK)
29+
@GetMapping("/v1/sign-up/verifications/emails/{email}")
30+
fun verifyEmail(@Email @PathVariable email: String): IdExistsCheckResponse {
31+
// TODO email 중복 검사
32+
return IdExistsCheckResponse(false)
33+
}
34+
35+
@ResponseStatus(HttpStatus.CREATED)
36+
@PutMapping("/v1/sign-up/verifications/ids/{userId}/auth-code")
37+
fun createAuthenticationCode(@PathVariable userId: String) {
38+
// TODO 인증번호 재발송
39+
}
40+
41+
@ResponseStatus(HttpStatus.OK)
42+
@PostMapping("/v1/sign-up/verifications/ids/{userId}/auth-code")
43+
fun verifyAuthenticationCode(@PathVariable userId: String, @RequestBody code: String) {
44+
// TODO 인증번호 검사
45+
}
46+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.sns.user.endpoints.user.requests
2+
3+
import javax.validation.constraints.Email
4+
import javax.validation.constraints.NotEmpty
5+
import org.hibernate.validator.constraints.Length
6+
7+
data class SignUpRequest(
8+
@NotEmpty
9+
@Length(max = 15)
10+
val name: String,
11+
@NotEmpty
12+
@Length(min = 8, max = 30)
13+
val password: String,
14+
@NotEmpty
15+
@Email
16+
val email: String,
17+
) {
18+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
package com.sns.user.endpoints.user.responses
2+
3+
data class IdExistsCheckResponse(
4+
val exist: Boolean
5+
) {
6+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,19 @@
11
CREATE TABLE IF NOT EXISTS `user`
22
(
33
id VARCHAR(50) NOT NULL PRIMARY KEY COMMENT '아이디 (이메일)',
4+
email_address VARCHAR(50) NOT NULL COMMENT '이메일 주소',
45
password VARCHAR(100) NOT NULL COMMENT '비밀번호',
56
`name` VARCHAR(50) NOT NULL COMMENT '이름',
67
info_email_address VARCHAR(50) NOT NULL COMMENT '서비스 정보 수신 이메일주소',
8+
authenticated_at DATETIME NULL COMMENT '이메일 인증 시각',
79
created_at DATETIME NOT NULL COMMENT '생성 시간',
810
updated_at DATETIME NOT NULL COMMENT '마지막 수정 시간'
911
);
12+
13+
14+
CREATE TABLE IF NOT EXISTS `sign_up_auth_code`
15+
(
16+
id VARCHAR(50) NOT NULL PRIMARY KEY COMMENT 'user.id',
17+
auth_code VARCHAR(50) NOT NULL COMMENT '인증 코드',
18+
created_at DATETIME NOT NULL COMMENT '생성 시각'
19+
);

0 commit comments

Comments
 (0)