SpringBoot Security
์ฐ๋ฆฌ๊ฐ ์ํ๋๋๋ก ์ ์ฐํ๊ฒ ์ปค์คํ ํ๋ ๊ฒ์ด ๊ฐ๋ฅํ๋ค!
์ค์ ํ๊ธฐ ์ํด์๋ pom.xml์์ spring-boot-starter-security ๋ผ๋ ์์กด์ฑ์ ์ถ๊ฐํด์ค์ผํ๋ค
AuthenticationManager bean์ ๋ฑ๋กํด์ค๋ค. ๊ทธ๋ฌ๋ฉด default๋ก ๋ฉ๋ชจ๋ฆฌ์ ํ๋์ ์ฌ์ฉ์๋ฅผ ๋ฑ๋ก์์ผ์ค๋ค(user๋ผ๋ ์ด๋ฆ, pw๋ ์ฝ์์ฐฝ์ ๋จ๊ฒ ๋๋ค)
static resource์ ์๋์ผ๋ก ๋ฌด์ํ๋ค = ๋ณด์์ด ํ์ ์๋ค
๋ค์ํ ํน์ง๋ค์ ํ์ฑํ์์ผ์ค๋ค. - XSS, CSRF ๋ฑ๋ฑ
์ ๋ ๊ฒ pom.xml์ ์ถ๊ฐ๋ง ํด์ค๋ ์๋์ผ๋ก ์ธ์ฆ์ ์ฐจ๋ฅผ ๋ฐ์์ผ๋ง ์นํ์ด์ง์ ์ ๊ทผํ ์ ์๋๋ก ๋ฐ๋๊ฒ๋๋ค โ default๋ก ๋ง๋ค์ด์ง user/์ฝ์์์๋ ๋น๋ฐ๋ฒํธ ์ด๊ฑธ ๊ฐ์ง๊ณ ๋ก๊ทธ์ธ์ ํ๋ฉด ์ ์์ ์ผ๋ก ์ ์ํ๋๊ฒ์ด ๊ฐ๋ฅํ๋ค
๋ง์ฝ ๋ค๋ฅธ ์ฌ์ฉ์๋ฅผ ๋ฃ์ด์ฃผ๊ณ ์ถ๋ค๋ฉด application.properties์์
spring.security.user.name = ์ฌ์ฉ์์ด๋ฆ
spring.security.user.password = ์ฌ์ฉ์๋น๋ฐ๋ฒํธ
spring.security.user.roles = USER, ADMIN
์ด๊ฑฐ๊ฐ์ ๊ฒฝ์ฐ์๋ ๊ตณ์ด ROLE_USER์ด๋ ๊ฒ ์ํด๋ ๊ด์ฐฎ์๊ฒ ์ด์งํผ ์๋์ ์ผ๋ก ์์ ROLE_ ์ด ๋ถ๊ฒ ๋์ด์๋ค!
ํ์ง๋ง ์ด๋ฐ ์ค์ ๋ค์ ๋ฐ๋ก db์ ์ค์ ํด์ฃผ์ง ์์์๊ฒฝ์ฐ์ ๋ฐ๋ก ๋ง๋ค์ด์ค ๊ฒฝ์ฐ์ด๋ค
WebMvcConfigure๋ผ๋ interface๋ฅผ implementsํ WebConfig๋ผ๋ ํด๋์ค๋ฅผ ๋ง๋ค๊ณ , addViewControllers์ ์ค๋ฒ๋ผ์ด๋ฉ ํด์ค์ผํ๋ค. ์์๋ ViewControllerRegistry registry.addViewController("/").setViewName("home");
Spring Security with thymeleaf
pox.xml์ thymleaf-extras-springsecurity5 ์ถ๊ฐ!
์ด๋ ๊ฒ ํด์ฃผ๋ฉด ์ผ๋ฐ ์ปจํธ๋กค๋ฌ์์ RequestMapping("/")์๋ค๊ฐ return "home"ํ๋ ํจ์์ ๊ฐ์ ์ญํ ์ ํด์ค๋ค = ์ฝ๋๊ฐ ์ค์ด๋ ๋ค!
SpringSecurityDialect์ bean์ผ๋ก ๋ฑ๋ก์์ผ์ค์ผํจ
SpringSecurityDialect๋? thymeleaf์ extra module์ด๊ณ , Spring MVC์ thymeleaf์ ํตํฉํด์ฃผ๋์ญํ ์ ํ๋ค.
thymeleaf์์ ๊ถํ์ด ์์๋๋ฅผ ํ์ธํ๋ ๋ฐฉ๋ฒ์
sec:authorize = "hasRole('USER')" : ๊ถํ์ด ํต๊ณผ๋๋ฉด ์ถ๋ ฅํด์ฃผ๋
sec:authentication="์ด๋ฆ์ด๋ ๊ถํ" : ์ด๋ฆ์ด๋ ๊ถํ์ ์ถ๋ ฅํด์ฃผ๋
Configure Spring Security
Role-based access control using a database
UserDetailsService to get UserDetails from database โ loadUserByUsername()์ ํตํด์ service์ ์๋ ๊ฐ๋ค์ UserDetails์๋ค๊ฐ ๋ฃ์ด์ค๋ค!
Customized Spring Security Configuration
pom.xml์๋ค๊ฐ spring-boot-starter-data-jpa์ ๋ฃ์ด์ฃผ๊ณ , mysql-connector-java ์ ๋ฃ์ด์ค์ผํจ
application.properties์๋ค๊ฐ DataSource์ ๋ํ ์ธํ ์ ํด์ฃผ๊ณ , JPA์ ๋ํ ์ธํ ์ ํด์ฃผ๊ณ , ๋ก๊น ๋ ํด์ฃผ๊ณ
UserDetailsService
์ฌ์ฉ์์ request๊ฐ ์ค๊ฒ๋๋ฉด AuthenticationFilter๋ฅผ ๊ฑฐ์น๋ค
AuthenticationFilter๋ฅผ ๊ฑฐ์น๋ฉด์ ์๊ธด ํ ํฐ์ AuthenticationManager์๊ฒ ๊ฑด๋ด์ฃผ๊ณ
AuthenticationManager๋ AuthenticationProvider(db์ ์ฐ๊ด๋์ด์๋)์๊ฒ ๊ฑด๋ด๊ฒ๋๋ค.
AuthenticationProvider๋ PasswordEncoder์ UserDetailsService์ ์ฐ๊ด์ด ๋์ด์๋ค.
์ฌ์ฉ์๊ฐ ๋ก๊ทธ์ธํ์๋ PasswordEncoder๋ฅผ ๊ฑฐ์น๋ฉด, ํด์ฌ๋ ๊ฐ์ ๋์ค๊ฒ๋๋ค
์ฌ๊ธฐ์ PasswordEncoder๋ฅผ ๋น์ผ๋ก ๋ฑ๋ก์ ํด์ฃผ๊ณ , ๊ทธ ์์์ BCryptPasswordEncoder()์ ์ฌ์ฉํ๋ค! โ ๋ฐ์ Spring Security Configuration ์ค์ ์
UserDetailService์๋ loadUserByUserName()์ด ์์ด์ loadUserByUserName()์ด DB๋ฅผ ๊ฑฐ์ณ์ UserDetails๋ฅผ ๊ฐ์ง๊ณ ์จ๋ค
AuthenticationProvider๊ฐ UserDetailService๋ฅผ ์ฌ์ฉํ๊ณ ์๊ณ , UserDetailsService๊ฐ loadUserByUserName()์ ์ฌ์ฉํด์ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ๊ฐ์ฒด๋ฅผ ๊บผ๋ด์จ๋ค.
์ฌ๊ธฐ์ UserDetailService๋ฅผ ๋ง์๋๋ก ์ปค์คํฐ๋ง์ด์ฆํด์ ํ์ฉํ๋ฉด ๋๋ค!
Spring Security Configuration
@Configuration, @EnableWebSecurity์ด ๋ค์ด๊ฐ๊ณ
WebSecurityConfigurerAdapter๋ฅผ ์์๋ฐ๋ ํด๋์ค๋ฅผ ๋ง๋ ๋ค.
๋ง๋ ํด๋์ค๋ Spring Security์ ๊ดํ ์ค์ ๋ค์ด ๋ค์ด๊ฐ๋ ํด๋์ค์ด๋ค
์ ์ ๋ง๋ค์๋ ์ปค์คํ UserDetailsService๋ฅผ @Autowired๋ก ๊ฐ์ ธ์์ฃผ๊ณ , PasswordEncoder(BCryptPasswordEncoder)์ ๋น์ผ๋ก ๋ฑ๋กํด์ฃผ๊ณ ,
configureGlobal(AuthenticationManagerBuilder auth)๋ก ์์ UserDetailsService์ PasswordEncoder๋ฅผ ๋ฑ๋กํด์ค๋ค
BCryptPasswordEncoder
random number์ธ salt์ ์ด์ฉํด์ hash password์ ๋ง๋ค์ด ๋ธ๋ค.
$๊ธฐ์ค์ผ๋ก ๋๋๊ณ
2a : BCrypt ์๊ณ ๋ฆฌ์ฆ ๋ฒ์
10 : ์๊ณ ๋ฆฌ์ฆ์ ๊ฐ๋
16๊ธ์ : ๋๋ค์ผ๋ก ๋ง๋ค์ด์ง 16it์ salt๋ฒํธ
๋จ์๊ฒ : plain text(31๊ธ์)
plaintext๋ PasswordEncoder encoder.encode("์ํ๋๋ฌธ์")
์ด๋ ๊ฒ ๋ฃ์ด์ ๋ง๋๋ฌ๋
Other Authorization
configure๋ผ๋ ํด๋์ค์์ ๋งค๊ฐ๋ณ์๋ก HttpSecurity http๋ก ์ ์ธํ๊ณ
http.authorizeRequests()
.antMatchers("url").permitAll()
.antMatchers("url").hasRole("ROLE")
.anyRequest().authenticated()
.and()๋ก ๋ค์๊ป๋ก ์ด์ด์ค
http.formLogin()
.loginPage("")
.defaultSuccessUrl("")
.failureUrl("")
.permitAll()
.and()๋ก ๋ค์๊ป๋ก ์ด์ด์ค
logout()
logoutRequestMatcher()
.logoutSuccessUrl()
.permitAll()
.and()
Create View Thymeleaf
sec:authorize = "isAuthenticated()"
๋ง์ฝ ์ธ์ฆ๋ ์ฌ์ฉ์๊ฐ ์ ๊ทผ์, ํ์ํด์ค
sec:authorize = "isAnonymous()"
์ธ์ฆ๋์ง ์์ ์ฌ์ฉ์๊ฐ ์ ๊ทผ์ ํ์
sec:authorize = "hasRole('ROLE_USER')"
ROLE_USER๋ผ๋ ๊ถํ์ ๊ฐ์ง ์ฌ๋์๊ฒ ํ์
CSRF
CSRF์ ๋ฐฉ์งํ๊ธฐ ์ํด์๋ ๊ธฐ๋ณธ์ผ๋ก enable()๋์ด์๊ธฐ ๋๋ฌธ์ ๋ง์ฝ์ ํ ์คํธ๋ฅผ ์ํด์ ์ด์ด๋ณด๊ณ ์ถ๋ค๋ฉด HttpSecurity http.csrf().disable(); ์ ํตํด์ ์ด์ ์์
CSRF token์ request์ ํจ๊ป ๋ณด๋ด์ ์ ์์ ์ธ ๊ณต๊ฒฉ์ด ์๋์ ์๋ ค์ผํ๋๋ฐ, ์๋ ์๋์ผ๋ก formํ๊ทธ์ ๋ค์ด๊ฐ์๊ฒ๋๋ค
SignUp Page์ ๋ง๋ค์ด๋ณด์
๋ง๋ค์ด์ผํ๋ ๊ฒ๋ค
RegistrationService Interface
RegistrationServiceImpl Class
RegistrationController Class
Signup.html
Last updated
Was this helpful?