login, logout 동작 추가.

cks
강석 최 2023-11-27 15:16:45 +09:00
parent 701047e22e
commit c5c3dd3850
7 changed files with 140 additions and 43 deletions

View File

@ -12,8 +12,7 @@ function EgovHeader({ loginUser, onChangeLogin }) {
console.log("[Start] EgovHeader ------------------------------");
const sessionUser = getSessionItem('loginUser');
const sessionUserId = sessionUser?.id;
const sessionUserName = sessionUser?.name;
const sessionUserId = sessionUser?.userId;
const sessionUserSe = sessionUser?.userSe;
const navigate = useNavigate();
@ -85,7 +84,7 @@ function EgovHeader({ loginUser, onChangeLogin }) {
{/* 로그아웃 : 로그인 정보 있을때 */}
{sessionUserId &&
<>
<span className="person">{sessionUserName} </span> 님이, 관리자로 로그인하셨습니다.
<span className="person">{sessionUserId} </span> 님이, {sessionUserSe==='ADM'?'관리자':'사용자'}로그인하셨습니다.
<button onClick={logOutHandler} className="btn">로그아웃</button>
</>
}
@ -161,7 +160,7 @@ function EgovHeader({ loginUser, onChangeLogin }) {
{/* 로그아웃 : 로그인 정보 있을때 */}
{sessionUserId &&
<>
<span className="person">{sessionUserName} </span> 로그인하셨습니다.
<span className="person">{sessionUserId} </span> 로그인하셨습니다.
<button onClick={logOutHandler} className="btn logout">로그아웃</button>
</>
}

View File

@ -62,7 +62,7 @@ function EgovLoginContent(props) {
const submitFormHandler = (e) => {
console.log("EgovLoginContent submitFormHandler()");
const loginUrl = "/login"
const loginUrl = "/auth/login"
const requestOptions = {
method: "POST",
headers: {
@ -74,7 +74,6 @@ function EgovLoginContent(props) {
EgovNet.requestFetch(loginUrl,
requestOptions,
(resp) => {
debugger
let resultVO = resp.resultVO;
let jToken = resp?.jToken || null;
@ -108,28 +107,26 @@ function EgovLoginContent(props) {
<p className="txt">전자정부표준프레임워크 경량환경 홈페이지 로그인 페이지입니다.<br />로그인을 하시면 모든 서비스를 제한없이 이용하실 있습니다.</p>
<div className="login_box">
<form name="" method="" action="" onSubmit={submitFormHandler}>
<fieldset>
<legend>로그인</legend>
<span className="group">
<fieldset>
<legend>로그인</legend>
<span className="group">
<input type="text" name="" title="아이디" placeholder="아이디" value={userInfo?.username}
onChange={e => setUserInfo({ ...userInfo, username: e.target.value })} />
onChange={e => setUserInfo({ ...userInfo, username: e.target.value })} />
<input type="password" name="" title="비밀번호" placeholder="비밀번호"
onChange={e => setUserInfo({ ...userInfo, password: e.target.value })} />
onChange={e => setUserInfo({ ...userInfo, password: e.target.value })} />
</span>
<Row className="chk justify-content-between">
<Col xs={3}>
<label className="f_chk" htmlFor="saveid" ref={checkRef}>
<input type="checkbox" name="" id="saveid" onChange={handleSaveIDFlag} checked={saveIDFlag}/> <em>ID저장</em>
</label>
</Col>
<Col xs={3}>
<Link to={URL.JOIN}><em>회원가입</em></Link>
</Col>
</Row>
<button type="submit"><span>LOGIN</span></button>
</fieldset>
</form>
<Row className="chk justify-content-between">
<Col xs={3}>
<label className="f_chk" htmlFor="saveid" ref={checkRef}>
<input type="checkbox" name="" id="saveid" onChange={handleSaveIDFlag} checked={saveIDFlag}/> <em>ID저장</em>
</label>
</Col>
<Col xs={3}>
<Link to={URL.JOIN}><em>회원가입</em></Link>
</Col>
</Row>
<button type="button" onClick={submitFormHandler}><span>LOGIN</span></button>
</fieldset>
</div>
<ul className="list">

View File

@ -55,7 +55,7 @@ public class LoginVO implements Serializable{
@NotBlank(message = "비밀번호확인을 입력해주세요.")
private String passwordChk;
@Schema(description = "사용자 구분", allowableValues = {"GNR", "ENT", "USR"}, defaultValue = "USR")
@Schema(description = "사용자 구분", allowableValues = {"ADM", "USR"}, defaultValue = "USR")
private String userSe;
@Schema(description = "이름")

View File

@ -0,0 +1,40 @@
package com.dbnt.kcscbackend.config.security;
import com.dbnt.kcscbackend.auth.entity.UserInfo;
import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
@Configuration
public class CustomLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
MediaType jsonMimeType = MediaType.APPLICATION_JSON;
HashMap<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("resultCode", "200");
if (jsonConverter.canWrite(resultMap.getClass(), jsonMimeType)) {
jsonConverter.write(resultMap, jsonMimeType, new ServletServerHttpResponse(response));
}
}
}

View File

@ -0,0 +1,69 @@
package com.dbnt.kcscbackend.config.security;
import com.dbnt.kcscbackend.auth.entity.UserInfo;
import com.dbnt.kcscbackend.config.jwt.EgovJwtTokenUtil;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.MediaType;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.http.server.ServletServerHttpResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
@Configuration
public class CustomUrlAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler {
private final EgovJwtTokenUtil jwtTokenUtil = new EgovJwtTokenUtil();
private RequestCache requestCache = new HttpSessionRequestCache();
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws ServletException, IOException {
SavedRequest savedRequest = requestCache.getRequest(request, response);
if (savedRequest != null) {
requestCache.removeRequest(request, response);
clearAuthenticationAttributes(request);
}
UserInfo securityUser = null;
if (SecurityContextHolder.getContext().getAuthentication() != null) {
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
securityUser = (UserInfo) principal;
}
}
// application/json(ajax) 요청일 경우 아래의 처리!
MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
MediaType jsonMimeType = MediaType.APPLICATION_JSON;
String jwtToken = jwtTokenUtil.generateToken(securityUser);
securityUser.setPassword(null);
securityUser.setUserSeq(null);
HashMap<String, Object> resultMap = new HashMap<String, Object>();
resultMap.put("resultCode", "200");
resultMap.put("resultVO", (UserDetails)securityUser);
resultMap.put("jToken", jwtToken);
// String userName = jwtTokenUtil.getUserSeFromToken(jwtToken);
response.addHeader("Authorization", "BEARER "+jwtToken);
if (jsonConverter.canWrite(resultMap.getClass(), jsonMimeType)) {
jsonConverter.write(resultMap, jsonMimeType, new ServletServerHttpResponse(response));
}
}
public void setRequestCache(RequestCache requestCache) {
this.requestCache = requestCache;
}
}

View File

@ -22,7 +22,7 @@ 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 DEFAULT_LOGIN_REQUEST_URL = "/auth/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 =

View File

@ -27,9 +27,11 @@ import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.SavedRequest;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
import org.springframework.security.web.util.matcher.RegexRequestMatcher;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsConfigurationSource;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
@ -69,7 +71,7 @@ public class SecurityConfig {
// 인증 예외 List
private String[] AUTH_WHITELIST = {
"/",
"/login/**",
"/auth/login",
"/login",
"/auth/join",//회원가입
"/cmm/main/**.do", // 메인페이지
@ -128,28 +130,18 @@ public class SecurityConfig {
);
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
http.cors().and().addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class)
.exceptionHandling(exceptionHandlingConfigurer ->
exceptionHandlingConfigurer
.authenticationEntryPoint(new JwtAuthenticationEntryPoint())
);
http.cors().and().addFilterBefore(jsonUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.addFilterBefore(jsonUsernamePasswordAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/auth/logout")).logoutSuccessHandler(new CustomLogoutSuccessHandler());
return http.build();
}
@Bean
public AuthenticationSuccessHandler loginSuccessHandler() {
return (request, response, authentication) -> {
UserInfo info = (UserInfo)authentication.getPrincipal();
String jwtToken = jwtTokenUtil.generateToken(info);
// String userName = jwtTokenUtil.getUserSeFromToken(jwtToken);
response.addHeader("Authorization", "BEARER "+jwtToken);
};
}
@Bean
public AuthenticationFailureHandler loginFailureHandler(){
return (request, response, exception) -> {
@ -159,7 +151,7 @@ public class SecurityConfig {
@Bean
public JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter() {
JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter = new JsonUsernamePasswordAuthenticationFilter(objectMapper, loginSuccessHandler(), loginFailureHandler());
JsonUsernamePasswordAuthenticationFilter jsonUsernamePasswordAuthenticationFilter = new JsonUsernamePasswordAuthenticationFilter(objectMapper, new CustomUrlAuthenticationSuccessHandler(), loginFailureHandler());
jsonUsernamePasswordAuthenticationFilter.setAuthenticationManager(authenticationManager());
return jsonUsernamePasswordAuthenticationFilter;
}