= 로그인 SDL은 Knox EpTray, ID/PW, ADFS 로그인을 지원한다. == EpTray Knox EpTray 로그인은 Chrome, Edge 등 멀티 브라우저에서 가능하다. 사용자가 Knox에 로그인을 한 후 시스템에 접속을 하게 되면 EpTray값을 이용해 시스템 로그인을 한다. NOTE: Knox EpTray SSO 를 위한 연계 신청이 필요하다. (스테이지/운영) + 자세한 내용 안내 및 문의는 Knox Support (매뉴얼 > KnoxPortal NewEpTray 연계 가이드) 를 참조한다. === EpTray 적용 연계신청 과정에서 생성되는 *rsaprivkey8.pem* 파일을 + config.properties의 login.sso.knox-tray-private-key-path 경로에 넣어준다. CAUTION: *rsaprivkey8.pem* 파일이 없는 경우 아래와 같은 에러가 발생하므로 주의한다. image::newEpTrayUtil.png[Can not load new EpTray Private Key.png] === LoginPage.vue UI 에서 사용자 정보가 없을 경우 LoginPage.vue 페이지로 이동하게 되고 인증 절차를 시작한다. EpTray 연계를 위한 메서드 [source,javascript] ---- async loginByNewEpTray() { let loginResult = false; SDLUtil.showLoadingBar(true); await this.socConnect().then((data) => { this.newEpTrayKey = data; this.websocket.close(); }).catch((err) => { SDLUtil.alert(err); }); SDLUtil.showLoadingBar(false); if (this.newEpTrayKey) { if (this.newEpTrayKey.result === 'success') { const { userInfo, key } = this.newEpTrayKey; loginResult = await this.loginNewEpTray({ userInfo, key }); } else { SDLUtil.alert(`sdl.epTray.error.${this.newEpTrayKey.errorCode}`); } } if (!loginResult) { if (this.$route.query.token) { loginService.setToken(this.$route.query.token); document.location = `${SDLUtil.WEB_CONTEXT_PATH}/`; } } this.afterLoginProcess(loginResult); }, ---- [source,javascript] ---- socConnect() { return new Promise(((resolve, reject) => { const server = new WebSocket('wss://localhost:29283'); // <1> this.websocket = server; server.onopen = () => { server.send('{"rqtype":"getknoxsso","token":"","data":"KCC60TRAY0072"}'); // <2> server.onmessage = (event) => { const socketData = JSON.parse(event.data); if (socketData.rpcode === 'RETURN_SUCCESS') { resolve(JSON.parse(socketData.data)); } else { this.websocket.close(); let err; if (socketData.rpcode === 'EMPTY_BOX') err = 'sdl.epTray.rpCode.EMPTY_BOX'; else err = `sdl.epTray.rpCode.${socketData.detail}`; reject(err); } }; }; server.onerror = () => { const err = 'sdl.epTray.rpCode.CONNECTION_FAILED'; reject(err); }; })); }, ---- <1> WebSocket HOST 정보 <2> 발급받은 연계용 system ID === LoginController.java LoginController 에서는 EpTray값의 정보를 이용해 사용자를 로그인 한다. 이때 시스템 사용자가 아닐 경우, 등록 화면으로 이동하고, 정상적인 시스템 사용자일 경우 Token을 발급한다. GET /noauth/login/new-eptray [source,java] ---- @PostMapping("/noauth/login/new-eptray") @Operation(value = "", description = "knox new eptray 로그인") public JwtResponse loginByNewEptray(HttpServletRequest request, HttpServletResponse response, @RequestParam String encodeUserInfo, @RequestParam String encodeAesKey ) throws AccountException { loginInterceptorExecutor.applyPreLogin(request, response); User user = authenticationService.loginByNewEpTray(encodeUserInfo, encodeAesKey); user.setRecentLoginIp(webUtil.getClientIp(request)); JwtResponse jwtResponse = new JwtResponse(jwtUtil.generateToken(user), user.getUserId()); user.setJwt(jwtResponse.getJwtToken().split("\\.")[2]); loginInterceptorExecutor.applyPostLogin(request, response, user); return jwtResponse; } ---- == ADFS 로그인 NOTE: ADFS 통합인증 사이트 (https://adsso.sec.samsung.net) 에서 신청 후 사용해야 한다. + 자세한 내용은 해당 사이트를 참조하거나 전자통합인증3 (nextsso3@samsung.com) 으로 문의 한다. SDL에서는 ADFS 통합인증 사이트의 가이드를 참조하여 AD 로그인 샘플을 제공하고 있으며, 각 프로젝트 환경에 맞게 수정하여 사용한다. === 참고할 샘플 파일 * LoginPage.vue * AdLoginController.java * onelogin.saml.properties == 로그인/아웃 전,후 처리 로그인 전과 후, 로그아웃 전과 후 비즈니스 로직이 필요한 경우 LoginInterceptor를 상속받아 구현한다. LoginInterceptor 클래스는 아래와 같은 Interface를 제공한다. [source, java] ---- /** * 로그인 전 */ default void preLogin(HttpServletRequest request, HttpServletResponse response) { } /** * 로그인 후 */ default void postLogin(HttpServletRequest request, HttpServletResponse response, User user) { } /** * 로그아웃 전 */ default void preLogout(HttpServletRequest request, HttpServletResponse response, User user) { } /** * 로그아웃 후 */ default void postLogout(HttpServletRequest request, HttpServletResponse response, User user) { } ---- LoginInterceptor를 구현한 클래스는 LoginInterceptorExecutor에 의해 실행되며 Spring Bean으로 등록하고 SpringWebCofig에 아래와 같이 LoginInterceptorExecutor에 등록한다. [source, java] ---- @Bean public LoginInterceptorExecutor loginInterceptorExecutor() { List loginInterceptorList = new ArrayList<>(); loginInterceptorList.add(userUpdateInterceptor()); loginInterceptorList.add(loginOutLogInterceptor()); return new LoginInterceptorExecutor(loginInterceptorList); } ---- 아래는 로그인 후 사용자 정보를 update 하는 UserUpdateInterceptor의 일부분이다. [source, java] ---- @Override public void postLogin(HttpServletRequest request, HttpServletResponse response, User user) { String recentLoginIp = user.getRecentLoginIp(); Date recentLoginDatetime = user.getRecentLoginDatetime(); user.setLastLoginDate(recentLoginDatetime); user.setLastLoginIp(recentLoginIp); user.setRecentLoginDatetime(new Date()); user.setRecentLoginIp(webUtil.getClientIp(request)); user.setLastActivityTime(System.currentTimeMillis()); userService.updateUser(user); } ----