์ธ์ฆ ๋ฐ ๊ถํ ์ฒ๋ฆฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ
โข
๊ธฐ๋ณธ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐฉ์
โข
์ด๋ฒคํธ ํธ๋ค๋ฌ ๊ตฌํํ๊ธฐ
โฆ
๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ
โฆ
๋ก๊ทธ์ธ ์คํจ ์ฒ๋ฆฌ
โฆ
๋ก๊ทธ์์ ์ฑ๊ณต ์ฒ๋ฆฌ
โฆ
๋ก๊ทธ์์ ์คํจ ์ฒ๋ฆฌ
โฆ
์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
๊ธฐ๋ณธ ์ด๋ฒคํธ ์ฒ๋ฆฌ ๋ฐฉ์
โข
๋ก๊ทธ์ธ ์ฑ๊ณต
โข
๋ก๊ทธ์ธ ์คํจ
โข
๋ก๊ทธ์์ ์ฑ๊ณต
โข
๋ก๊ทธ์์ ์คํจ
โข
์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
์ด๋ฒคํธ ์ข
๋ฅ | ๊ธฐ๋ณธ ํธ๋ค๋ฌ | ๊ธฐ๋ณธ ์ฒ๋ฆฌ ๋ฐฉ์ |
๋ก๊ทธ์ธ ์ฑ๊ณต | SavedRequestAwareAuthenticationSuccessHandler | ์ด์ ์์ฒญ ๋๋ /๋ก ๋ฆฌ๋ค์ด๋ ํธ |
๋ก๊ทธ์ธ ์คํจ | SimpleUrlAuthenticationFailureHandler | ๋ก๊ทธ์ธ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ,
/login?error error ํ๋ผ๋ฏธํฐ ์ถ๊ฐ |
๋ก๊ทธ์์ ์ฑ๊ณต | SimpleUrlLogoutSuccessHandler | /login?logout logout ํ๋ผ๋ฏธํฐ ์ถ๊ฐ
๋๋ ์ค์ ๋ URL๋ก ๋ฆฌ๋ค์ด๋ ํธ |
๋ก๊ทธ์์ ์คํจ | (์คํจ ์ด๋ฒคํธ ์์) | 403 Forbidden ์๋ต |
์ ๊ทผ ๊ฑฐ๋ถ | AccessDeniedHandlerImpl | 403 Forbidden
๋๋ ์ค์ ๋ ์๋ฌ ํ์ด์ง๋ก ์ด๋ |
๋ก๊ทธ์ธ ์ฑ๊ณต
๋ก๊ทธ์ธ ์ฑ๊ณต ์, ๋ฃจํธ ๊ฒฝ๋ก โ/โ (index.html) ๋ฉ์ธํ๋ฉด์ผ๋ก ์ด๋ํ๋ค.
๋ก๊ทธ์ธ ์คํจ
๋ก๊ทธ์ธ ์คํจ ์, /login?error ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ค.
๋ก๊ทธ์์ ์ฑ๊ณต
๋ก๊ทธ์์ ์ฑ๊ณต ์, /login?logout ๋ก๊ทธ์ธ ํ๋ฉด์ผ๋ก ์ด๋ํ๋ค.
๋ก๊ทธ์์ ์คํจ
๋ก๊ทธ์์ ์คํจ ์ด๋ฒคํธ๋ ์์.
404 ์ด๊ฑฐ๋ 403(CSRF TOKEN) ๋ฑ์ ๋ก๊ทธ์์ ์์ฒญ ์์ ๋ฌธ์ ๋ก ๋ฐ์ํ๋ ์๋ฌ ์๋ต
์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
๊ถํ์ด ์๋ ์ฌ์ฉ์๊ฐ ํน์ ๊ถํ์ด ํ์ํ ํ์ด์ง๋ฅผ ์ ๊ทผ ํ ๋
ex) ์ฌ์ฉ์ (ROLE_USER) ๊ถํ์ ๊ฐ์ง ์ฌ์ฉ์๊ฐ ๊ด๋ฆฌ์ (ROLE_ADMIN) ๊ถํ์ด ํ์ํ ํ์ด์ง๋ฅผ ์์ฒญํ ๋, 403 Forbidden
Forbidden : ๊ธ์ง๋
์ด๋ฒคํธ ํธ๋ค๋ฌ ๊ตฌํํ๊ธฐ
โข
๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ
โข
๋ก๊ทธ์ธ ์คํจ ์ฒ๋ฆฌ
โข
๋ก๊ทธ์์ ์ฑ๊ณต ์ฒ๋ฆฌ
โข
๋ก๊ทธ์์ ์คํจ ์ฒ๋ฆฌ
โข
์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
โข
์คํ๋ง ์ํ๋ฆฌํฐ ์ค์
๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ
LoginSuccessHandler.java
/**
* ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ ์ด๋ฒคํธ ํธ๋ค๋ฌ
*/
@Slf4j
@Component
public class LoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler {
/**
* ๋ก๊ทธ์ธ ์ฑ๊ณต ์ ํธ์ถ๋๋ ๋ฉ์๋
* ๐ช ์์ด๋ ์ ์ฅ ์ฟ ํค ์์ฑ
* ๐ ๋ก๊ทธ์ธ ํ ์ด์ ํ์ด์ง๋ก ๋ฆฌ๋ค์ด๋ ํธ
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request
, HttpServletResponse response
, Authentication authentication) throws ServletException, IOException {
log.info("๋ก๊ทธ์ธ ์ฑ๊ณต...");
// ์ธ์ฆ๋ ์ฌ์ฉ์ ์ ๋ณด
CustomUser customUser = (CustomUser) authentication.getPrincipal();
Users user = customUser.getUser();
log.info("์์ด๋ : " + user.getUsername());
log.info("๋น๋ฐ๋ฒํธ : " + user.getPassword());
log.info("๊ถํ : " + user.getAuthList());
super.onAuthenticationSuccess(request, response, authentication);
}
}
Java
๋ณต์ฌ
๋ก๊ทธ์ธ ์คํจ ์ฒ๋ฆฌ
LoginFailureHandler.java
/**
* ๋ก๊ทธ์ธ ์คํจ ์ฒ๋ฆฌ์
*/
@Slf4j
@Component
public class LoginFailureHandler implements AuthenticationFailureHandler {
/**
* ๋ก๊ทธ์ธ ์คํจ ์, ํธ์ถ๋๋ ๋ฉ์๋
* ๐โ ๋ก๊ทธ์ธ ์คํจ ํ์ ์ฒดํฌ, ๋ณด์ ์ฒ๋ฆฌ
* ( ๋ก๊ทธ์ธ ์คํจ 5ํ ๋์ ์, ๋ณธ์ธ์ธ์ฆ ๋ฑ ์์ฒญ )
*/
@Override
public void onAuthenticationFailure(HttpServletRequest request
, HttpServletResponse response
, AuthenticationException exception) throws IOException, ServletException {
log.info("๋ก๊ทธ์ธ ์ฒ๋ฆฌ ์คํจ...");
// ๋ก๊ทธ์ธ ํ์ด์ง๋ก ์๋ฌ ํฌํจ ์ ๋ฌ
response.sendRedirect("/login?error");
}
}
Java
๋ณต์ฌ
๋ก๊ทธ์์ ์ฑ๊ณต ์ฒ๋ฆฌ
LogoutSuccesshandler.java
Java
๋ณต์ฌ
๋ก๊ทธ์์ ์คํจ ์ฒ๋ฆฌ
๋ก๊ทธ์์ ์คํจ ์ด๋ฒคํธ๋ ์์
์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ
AccessDeniedHandler.java
@Slf4j
@Component
public class CustomAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request
, HttpServletResponse response
, AccessDeniedException accessDeniedException) throws IOException, ServletException {
log.info("์ ๊ทผ ๊ถํ์ด ์์ต๋๋ค.");
// ์๋ฌ ํ์ด์ง๋ก ์ด๋
response.sendRedirect("/error/403");
}
}
Java
๋ณต์ฌ
์คํ๋ง ์ํ๋ฆฌํฐ ์ค์
SecurityConfig.java
@Slf4j
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailServiceImpl userDetailServiceImpl;
@Autowired
private LoginSuccessHandler loginSuccessHandler;
@Autowired
private LoginFailureHandler loginFailureHandler;
@Autowired
private CustomAccessDeniedHandler customAccessDeniedHandler;
// ์คํ๋ง ์ํ๋ฆฌํฐ ์ค์ ๋ฉ์๋
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// โ
์ธ๊ฐ ์ค์
http.authorizeHttpRequests(auth -> auth
.requestMatchers("/admin", "/admin/**").hasRole("ADMIN")
.requestMatchers("/user", "/user/**").hasAnyRole("USER","ADMIN")
.requestMatchers("/**").permitAll()
.anyRequest().permitAll()
);
// ๐ ํผ ๋ก๊ทธ์ธ ์ค์
// โ
์ปค์คํ
๋ก๊ทธ์ธ ํ์ด์ง
http.formLogin(login -> login.usernameParameter("id") // ์์ด๋ ํ๋ผ๋ฏธํฐ
.passwordParameter("pw") // ๋น๋ฐ๋ฒํธ ํ๋ผ๋ฏธํฐ
.loginPage("/login") // ๋ก๊ทธ์ธ ํ์ด์ง ๊ฒฝ๋ก
.loginProcessingUrl("/login") // ๋ก๊ทธ์ธ ์์ฒญ ๊ฒฝ๋ก
// .defaultSuccessUrl("/?success") // ๋ก๊ทธ์ธ ์ฑ๊ณต ๊ฒฝ๋ก
.successHandler(loginSuccessHandler) // ๋ก๊ทธ์ธ ์ฑ๊ณต ์ฒ๋ฆฌ์ ์ค์
// .failureUrl("/login?error") // ๋ก๊ทธ์ธ ์คํจ ๊ฒฝ๋ก
.failureHandler(loginFailureHandler) // ๋ก๊ทธ์ธ ์คํจ ์ฒ๋ฆฌ์ ์ค์
)
;
// ๐ฉโ๐ผ ์ฌ์ฉ์ ์ ์ ์ธ์ฆ
http.userDetailsService(userDetailServiceImpl);
// ๐ ์๋ ๋ก๊ทธ์ธ ์ค์
http.rememberMe(me -> me.key("aloha")
.rememberMeParameter("auto-login")
.tokenRepository(tokenRepository())
.tokenValiditySeconds(60 * 60 * 24 * 7)); // 7์ผ ์ ํจ์๊ฐ (์ด๋จ์)
// ์ธ์ฆ ์์ธ ์ฒ๋ฆฌ
http.exceptionHandling( exception -> exception
// ์์ธ ์ฒ๋ฆฌ ํ์ด์ง ์ค์
// .accessDeniedPage("/exception")
// ์ ๊ทผ ๊ฑฐ๋ถ ์ฒ๋ฆฌ์ ์ค์
.accessDeniedHandler(customAccessDeniedHandler)
);
return http.build();
}
/**
* ๐ ๋น๋ฐ๋ฒํธ ์ํธํ ๋น ๋ฑ๋ก
* @return
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* ๐ AuthenticationManager ์ธ์ฆ ๊ด๋ฆฌ์ ๋น ๋ฑ๋ก
* @param authenticationConfiguration
* @return
* @throws Exception
*/
@Bean
public AuthenticationManager authenticationManager(
AuthenticationConfiguration authenticationConfiguration ) throws Exception {
return authenticationConfiguration.getAuthenticationManager();
}
/**
* ๐ JDBC ์ธ์ฆ ๋ฐฉ์ ๋น ๋ฑ๋ก
* @return
*/
// @Bean
// public UserDetailsService userDetailsService() {
// JdbcUserDetailsManager userDetailsManager
// = new JdbcUserDetailsManager(dataSource);
// // ์ฌ์ฉ์ ์ธ์ฆ ์ฟผ๋ฆฌ
// String sql1 = " SELECT username, password, enabled "
// + " FROM user "
// + " WHERE username = ? "
// ;
// // ์ฌ์ฉ์ ๊ถํ ์ฟผ๋ฆฌ
// String sql2 = " SELECT username, auth "
// + " FROM user_auth "
// + " WHERE username = ? "
// ;
// userDetailsManager.setUsersByUsernameQuery(sql1);
// userDetailsManager.setAuthoritiesByUsernameQuery(sql2);
// return userDetailsManager;
// }
/**
* ๐ ์๋ ๋ก๊ทธ์ธ ์ ์ฅ์ ๋น ๋ฑ๋ก
* โ
๋ฐ์ดํฐ ์์ค
* โญ persistent_logins ํ
์ด๋ธ ์์ฑ
create table persistent_logins (
username varchar(64) not null
, series varchar(64) primary key
, token varchar(64) not null
, last_used timestamp not null
);
* ๐ ์๋ ๋ก๊ทธ์ธ ํ๋ก์ธ์ค
* โ
๋ก๊ทธ์ธ ์
* โก ๐ฉโ๐ผ(ID, ์๋ฆฌ์ฆ, ํ ํฐ) ์ ์ฅ
* โ
๋ก๊ทธ์์ ์,
* โก ๐ฉโ๐ผ(ID, ์๋ฆฌ์ฆ, ํ ํฐ) ์ญ์
* @return
*/
@Bean
public PersistentTokenRepository tokenRepository() {
// JdbcTokenRepositoryImpl : ํ ํฐ ์ ์ฅ ๋ฐ์ดํฐ ๋ฒ ์ด์ค๋ฅผ ๋ฑ๋กํ๋ ๊ฐ์ฒด
JdbcTokenRepositoryImpl repositoryImpl = new JdbcTokenRepositoryImpl();
// โ
ํ ํฐ ์ ์ฅ์๋ฅผ ์ฌ์ฉํ๋ ๋ฐ์ดํฐ ์์ค ์ง์
// - ์ํ๋ฆฌํฐ๊ฐ ์๋ ๋ก๊ทธ์ธ ํ๋ก์ธ์ค๋ฅผ ์ฒ๋ฆฌํ๊ธฐ ์ํ DB๋ฅผ ์ง์ ํฉ๋๋ค.
repositoryImpl.setDataSource(dataSource);
// ์๋ฒ ์คํ ์, ์๋ ๋ก๊ทธ์ธ ํ
์ด๋ธ ์๋ ์์ฑ
// repositoryImpl.setCreateTableOnStartup(true);
// persistent_logins ํ
์ด๋ธ ์์ฑ
try {
repositoryImpl.getJdbcTemplate().execute(JdbcTokenRepositoryImpl.CREATE_TABLE_SQL);
}
catch (BadSqlGrammarException e) {
log.error("persistent_logins ํ
์ด๋ธ์ด ์ด๋ฏธ ์กด์ฌํฉ๋๋ค.");
}
catch (Exception e) {
log.error("์๋ ๋ก๊ทธ์ธ ํ
์ด๋ธ ์์ฑ ์ค , ์์ธ ๋ฐ์");
}
return repositoryImpl;
}
}
Java
๋ณต์ฌ