로그인 기능 작업중.

cks
강석 최 2023-11-23 18:03:39 +09:00
parent 40318e86ef
commit 8738a08189
5 changed files with 138 additions and 40 deletions

View File

@ -62,7 +62,7 @@ function EgovLoginContent(props) {
const submitFormHandler = (e) => { const submitFormHandler = (e) => {
console.log("EgovLoginContent submitFormHandler()"); console.log("EgovLoginContent submitFormHandler()");
const loginUrl = "/auth/login" const loginUrl = "/login"
const requestOptions = { const requestOptions = {
method: "POST", method: "POST",
headers: { headers: {

View File

@ -101,30 +101,4 @@ public class EgovLoginApiController extends BaseController {
} }
return resultMap; return resultMap;
} }
/**
* .
* @return resultVO
* @exception Exception
*/
@Operation(
summary = "로그아웃",
description = "로그아웃 처리(JWT,일반 관계 없이)",
tags = {"EgovLoginApiController"}
)
@ApiResponses(value = {
@ApiResponse(responseCode = "200", description = "로그아웃 성공"),
})
@GetMapping(value = "/logout")
public ResultVO actionLogoutJSON(HttpServletRequest request, HttpServletResponse response) throws Exception {
ResultVO resultVO = new ResultVO();
new SecurityContextLogoutHandler().logout(request, response, null);
resultVO.setResultCode(ResponseCode.SUCCESS.getCode());
resultVO.setResultMessage(ResponseCode.SUCCESS.getMessage());
return resultVO;
}
} }

View File

@ -0,0 +1,76 @@
package com.dbnt.kcscbackend.config.security;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.util.StreamUtils;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
@Slf4j
public class JsonUsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private static final String DEFAULT_LOGIN_REQUEST_URL = "/login"; // /login/oauth2/ + ????? 로 오는 요청을 처리할 것이다
private static final String HTTP_METHOD = "POST"; //HTTP 메서드의 방식은 POST 이다.
private static final String CONTENT_TYPE = "application/json";//json 타입의 데이터로만 로그인을 진행한다.
private static final AntPathRequestMatcher DEFAULT_LOGIN_PATH_REQUEST_MATCHER =
new AntPathRequestMatcher(DEFAULT_LOGIN_REQUEST_URL, HTTP_METHOD); //=> /login 의 요청에, POST로 온 요청에 매칭된다.
private final ObjectMapper objectMapper;
public JsonUsernamePasswordAuthenticationFilter(ObjectMapper objectMapper,
AuthenticationSuccessHandler authenticationSuccessHandler, // 로그인 성공 시 처리할 핸들러
AuthenticationFailureHandler authenticationFailureHandler // 로그인 실패 시 처리할 핸들러
) {
super(DEFAULT_LOGIN_PATH_REQUEST_MATCHER); // 위에서 설정한 /oauth2/login/* 의 요청에, GET으로 온 요청을 처리하기 위해 설정한다.
this.objectMapper = objectMapper;
setAuthenticationSuccessHandler(authenticationSuccessHandler);
setAuthenticationFailureHandler(authenticationFailureHandler);
}
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException {
if (request.getContentType() == null || !request.getContentType().equals(CONTENT_TYPE)) {
throw new AuthenticationServiceException("Authentication Content-Type not supported: " + request.getContentType());
}
LoginDto loginDto = objectMapper.readValue(StreamUtils.copyToString(request.getInputStream(), StandardCharsets.UTF_8), LoginDto.class);
String username = loginDto.getUsername();
String password = loginDto.getPassword();
if (username == null || password == null) {
throw new AuthenticationServiceException("DATA IS MISS");
}
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void setDetails(HttpServletRequest request, UsernamePasswordAuthenticationToken authRequest) {
authRequest.setDetails(this.authenticationDetailsSource.buildDetails(request));
}
@Data
private static class LoginDto {
String username;
String password;
}
}

View File

@ -1,17 +1,27 @@
package com.dbnt.kcscbackend.config.security; package com.dbnt.kcscbackend.config.security;
import com.dbnt.kcscbackend.auth.entity.UserInfo; import com.dbnt.kcscbackend.auth.entity.UserInfo;
import com.dbnt.kcscbackend.auth.service.EgovLoginService;
import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil; import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil;
import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationEntryPoint; import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationEntryPoint;
import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationFilter; import com.dbnt.kcscbackend.config.jwt.JwtAuthenticationFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod; import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer; import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.crypto.password.Pbkdf2PasswordEncoder;
import org.springframework.security.web.DefaultRedirectStrategy; import org.springframework.security.web.DefaultRedirectStrategy;
import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler; import org.springframework.security.web.authentication.AuthenticationFailureHandler;
@ -24,6 +34,7 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import javax.annotation.Resource;
import javax.servlet.http.HttpSession; import javax.servlet.http.HttpSession;
import java.util.Arrays; import java.util.Arrays;
@ -39,10 +50,14 @@ import java.util.Arrays;
*/ */
@Configuration @Configuration
@EnableWebSecurity @EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig { public class SecurityConfig {
@Autowired @Autowired
private EgovJwtTokenUtil jwtTokenUtil; private EgovJwtTokenUtil jwtTokenUtil;
@Resource(name = "loginService")
private UserDetailsService loginService;
private final ObjectMapper objectMapper;
//Http Methpd : Get 인증예외 List //Http Methpd : Get 인증예외 List
private String[] AUTH_GET_WHITELIST = { private String[] AUTH_GET_WHITELIST = {
@ -55,6 +70,7 @@ public class SecurityConfig {
private String[] AUTH_WHITELIST = { private String[] AUTH_WHITELIST = {
"/", "/",
"/login/**", "/login/**",
"/login",
"/auth/login-jwt",//JWT 로그인 "/auth/login-jwt",//JWT 로그인
"/auth/login",//일반 로그인 "/auth/login",//일반 로그인
"/auth/join",//회원가입 "/auth/join",//회원가입
@ -107,22 +123,26 @@ public class SecurityConfig {
.antMatchers(AUTH_WHITELIST).permitAll() .antMatchers(AUTH_WHITELIST).permitAll()
.antMatchers(HttpMethod.GET,AUTH_GET_WHITELIST).permitAll() .antMatchers(HttpMethod.GET,AUTH_GET_WHITELIST).permitAll()
.anyRequest().authenticated() .anyRequest().authenticated()
).sessionManagement((sessionManagement) -> );
http.sessionManagement((sessionManagement) ->
sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS) sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
) );
.cors().and()
.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class) http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(exceptionHandlingConfigurer -> .exceptionHandling(exceptionHandlingConfigurer ->
exceptionHandlingConfigurer exceptionHandlingConfigurer
.authenticationEntryPoint(new JwtAuthenticationEntryPoint()) .authenticationEntryPoint(new JwtAuthenticationEntryPoint())
) );
.cors().and()
.formLogin().loginProcessingUrl("/auth/login") http.httpBasic().disable()
.successHandler(loginSuccessHandler()) .csrf().disable()
.and().logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout")) .formLogin().disable();
.logoutSuccessUrl("/")
.invalidateHttpSession(true) // http.authorizeHttpRequests()
.deleteCookies("JSESSIONID"); // .requestMatchers(new AntPathRequestMatcher("/auth/login")).permitAll()
// .anyRequest().authenticated();
http.cors().and().addFilterBefore(jsonUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
return http.build(); return http.build();
} }
@ -138,5 +158,33 @@ public class SecurityConfig {
}; };
} }
@Bean
public AuthenticationFailureHandler loginFailureHandler(){
return (request, response, exception) -> {
new DefaultRedirectStrategy().sendRedirect(request, response, "/login-error");
};
}
@Bean
public JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter() {
JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter = new JsonUsernamePasswordAuthenticationFilter(objectMapper, loginSuccessHandler(), loginFailureHandler());
jsonUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());
return jsonUsernamePasswordAuthenticationFilter;
}
@Bean
public AuthenticationManager authenticationManager() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(passwordEncoder());
provider.setUserDetailsService(loginService);
return new ProviderManager(provider);
}
@Bean
public PasswordEncoder passwordEncoder() {
return new Pbkdf2PasswordEncoder();
}
} }

View File

@ -5,4 +5,4 @@ Globals.pageUnit=10
Globals.pageSize=10 Globals.pageSize=10
#JWT secret key #JWT secret key
Globals.jwt.secret = egovframe Globals.jwt.secret = qWwMroux3QtiIJcPSIZARNTZEBBnWVH0jZ2Lx7tfFChCYi0ViZllo1bekZdiU0B3FRjJI7g90n0ha120dwlz8JZU8rOkmNCe9Uq0