
회사에서 이번에 SSO 연동을 하게 됨.
AES256 암호화 알고리즘을 이용하기로 함.
간만에 java 만지게 됐다.
AES256 암호화 방식
AES256은 256비트(32바이트)의 대칭키를 사용한다.
이 대칭키는 암호화와 복호화에 모두 사용됨.
AES256은 블록 암호화 방식 중 하나로, 16바이트 크기의 블록 단위로 암호화를 수행한다.
입력된 평문은 블록 단위로 분할되어 각 블록마다 암호화가 수행된다.
* AES256 알고리즘은 구글링 하면 나옴
일단 임의로 토큰값을 받음
컨트롤러 하나 만들어줌
// 컨트롤러를 만든다.
@Controller
public class SSOController {
//로그를 찍기 위해 logger 생성
private static final Logger logger = LoggerFactory.getLogger(SendApprovalAlarmService.class);
/*
private static final Logger logger = LoggerFactory.getLogger(SendApprovalAlarmService.class);
로그 찍으려고 사용하는거임.
LoggerFactory.getLogger() 메서드를 호출해서
SendApprovalAlarmService.class의 인스턴스에 대한 Logger를 가져옴.
이를 통해 해당 클래스(여기서는 SendApprovalAlarmService)에서 로그를 찍을 수 있다.
*/
// RequestMapping 으로 SSO 적용할 주소 설정
@RequestMapping("/sso/Login")
public void ssoLogin(HttpServletRequest request) throws Exception {
// 위 코드에서 HttpServletRequest request는
// SSOController 클래스의 ssoLogin 메소드의 파라미터로 전달되며,
// 클라이언트가 전송한 암호화된 문자열을 받아들이고 복호화하는 역할을 수행함.
String empId = "";
String param_empId = "";
String param_stamp = "";
String key = "MOIN0KOREABLASTER17010120051010A";
/*
key는 이 SSO 통합 예제에서 암호화 및 복호화에 사용되는 대칭키를 나타내는 문자열 변수이다.
32자리 길이의 문자열이며,
AES256Cipher.AES_DecodeUrl 메서드에서 암호화된 텍스트를 디코딩하는 데 사용된다.
*/
String encTxt = request.getParameter("v");
// HttpServletRequest 객체의 `getParameter` 메소드는
// 클라이언트가 요청한 HTTP 요청 데이터의 `v` 파라미터를 반환한다.
// 위 코드에서 `encTxt` 변수에 할당된 값은 `v` 파라미터를 디코딩하기 위한 암호화된 문자열이다.
logger.info(" encTxt : "+ encTxt); //로그 찍음
String decTxt = AES256Cipher.AES_DecodeUrl(encTxt, key);
/*
AES256Cipher.AES_DecodeUrl(encTxt, key)는 암호화된 문자열을 복호화하는 메소드이고,
encTxt는 암호화된 문자열을, key는 대칭키를 나타낸다.
이 메소드는 SSO 연동에 사용되는 암호화 기술 중 하나인 AES256을 사용하여
암호화된 문자열을 디코딩 한다.
*/
logger.info(" decTxt : "+ decTxt); //로그 찍음
JSONParser jsonParser = new JSONParser();
/*
`JSONParser` 클래스는 JSON 형식의 문자열을 파싱하는 데 사용된다.
`parse` 메소드를 사용하여 JSON 문자열을 `Object`로 변환함.
*/
JSONArray jsonArray = (JSONArray)jsonParser.parse(decTxt);
//`JSONArray`는 `Object`의 배열이며, `JSONObject`는 `Object`의 하위 항목이다.
//`jsonParser.parse(decTxt)`는 암호화된 JSON 문자열을 역직렬화하여 객체 배열로 변환
//`for`루프를 이요해 배열 내의 요소를 반복하고,
//`Key` 값이 "empno" 또는 "stamp"와 일치하는 요소에서 `Value` 값을 추출한다.
for (int i = 0; i < jsonArray.size(); i++) {
JSONObject obj = (JSONObject) jsonParser.parse(jsonArray.get(i).toString());
String jsonKey = obj.get("Key").toString();
String jsonValue = obj.get("Value").toString();
if(jsonKey.equals("empno")) {
empnoValue = jsonValue;
}
if(jsonKey.equals("stamp")) {
stampValue = jsonValue;
}
}
// empnoValue나 stampValue 안 들어있으면 errorView로 리다이렉트
if (StringUtils.isEmpty(empnoValue) || StringUtils.isEmpty(stampValue)) {
modelMap.addAttribute("message", "요청정보가 유효하지 않습니다.");
return "/unidocu-ui/errorView";
}
// 로그 찍음
logger.info(" id ==>>> "+ param_empId + "stamp ==>>>"+param_stamp);
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmm");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Date currentTimestamp = new Date();
Date paramTimestamp = sdf.parse(stampValue);
long diffMinutes = (currentTimestamp.getTime() - paramTimestamp.getTime()) / (60 * 1000);
// 만료된 세션이면 Error view로 리다이렉트
if (diffMinutes < -10 || diffMinutes > 10) {
logger.warn("유효하지 않은 세션입니다");
modelMap.addAttribute("message", "유효하지 않은 세션입니다.");
return "/unidocu-ui/errorView";
}
HttpSession session = request.getSession();
ImportParam importParam = new ImportParam();
importParam.put("PERNR", empnoValue);
importParam.put("LOGIN_TYPE", "S");
csReturn z9000 = namedService.call("z9000", importParam);
Map<String, String> user_info = z9000.getExportMap("USER_INFO");
UniUtil.getAuthorizedMenuInfo(z9000, user_info);
UniUserInfo uniUserInfo = loginService.handleLoginSuccess(user_info);
UniSession.<UniUserInfo>getUserInfoAttribute(session).getUserInfoMap().put("LOGIN_TYPE", "S");
uniUserInfo.setSSOUser(true);
return "redirect:/";
}
}
// 이를 통해 SSO 연동에서 사용되는 암호화된 JSON 문자열을 복호화하고,
// empno 및 stamp 값을 추출할 수 있음.
1. 패키지 및 필요한 import 선언 (생략함)
2.클래스 선언:
@Controller 어노테이션을 사용하여 Spring의 컨트롤러로 지정한다.
클래스명은 SSOController이며, NamedService와 LoginService를 주입받음
로깅을 위해 Logger 객체를 선언한다.
3. 생성자:
NamedService와 LoginService를 주입받는 생성자가 정의되어 있음.
4. ssoLogin 메서드:
@RequestMapping("/sso/Login") 어노테이션을 통해 "/sso/Login" 경로에 대한 요청을 처리한다.
HttpServletRequest와 ModelMap 객체를 매개변수로 받고,
해당 메서드는 예외를 던질 수 있으므로, throws Exception으로 선언되어 있음.
메서드 내에서 다음과 같은 작업을 수행한다.
요청에서 "v"라는 파라미터 값을 가져온다.
AES256Cipher.AES_DecodeUrl 메서드를 사용하여 encTxt를 복호화 한다.
JSONParser를 사용하여 복호화된 문자열을 JSON 배열로 파싱한다.
JSON 배열을 순회하면서 "empno"와 "stamp"라는 키에 해당하는 값을 추출함.
추출된 값들을 검증하고 필요한 처리를 수행한다.
세션 객체를 생성하고, 사용자 정보를 저장한다.
최종적으로 메인 페이지로 리다이렉트 시킨다.
호출하는 거 따로 만들어서 토큰값 인위적으로 넣고 empno 랑 stamp 잘 나오는 지 확인해보면 됨.
개발 블로그
포스팅이 좋았다면 "좋아요❤️" 누르기 !