Skip to content

Commit

Permalink
fix: 교내 사이트에 맞춰 ssoToken 적용
Browse files Browse the repository at this point in the history
  • Loading branch information
urinaner committed Jan 17, 2025
1 parent 53543e0 commit 49e508c
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 91 deletions.
2 changes: 1 addition & 1 deletion src/main/java/org/yj/sejongauth/controller/Sj.java
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public Sj(AuthService authService, ProfileService profileService){

public SjProfile login(String userId, String password) {
if (authService.authenticate(userId, password)) {
String jsessionId = authService.getJsessionId();
String jsessionId = authService.getSsoToken();
return profileService.fetchUserProfile(jsessionId);
} else {
throw new RuntimeException("인증에 실패하였습니다.");
Expand Down
82 changes: 25 additions & 57 deletions src/main/java/org/yj/sejongauth/domain/AuthService.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,101 +2,69 @@



import java.io.BufferedReader;
import java.io.IOException;
import java.io.OutputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Map;
import java.net.URLEncoder;
import org.springframework.stereotype.Service;

public class AuthService {
private String jsessionId;
private final String SJ_LOGIN_URL = "https://classic.sejong.ac.kr/userLogin.do";
private final String SJ_POTAL_URL = "https://classic.sejong.ac.kr";
private String ssoToken;
private final String PORTAL_LOGIN_URL = "https://portal.sejong.ac.kr/jsp/login/login_action.jsp";
private final String INVALID_AUTH = "인증이 실패하였습니다.";
private final String INVALID_SESSION = "SESSION_ID 가져오는 것을 실패하였습니다.";
private final String INVALID_SESSION = "SSO Token 가져오는 것을 실패하였습니다.";
private final String INVALID_URL = "URL이 유효하지 않습니다.";
private final String CONTAINS_HTML = "로그인 정보가 올바르지 않습니다.";

public boolean authenticate(String userId, String password) {
LoginReq loginReq = new LoginReq(userId, password);
try {
fetchJsessionId();
System.out.println(attemptLogin(loginReq));
return attemptLogin(loginReq);
} catch (IOException e) {
throw new RuntimeException(INVALID_AUTH);
}
}

void fetchJsessionId() throws IOException {
try {
URI uri = new URI(SJ_POTAL_URL);
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setRequestMethod("GET");
connection.connect();

Map<String, List<String>> headers = connection.getHeaderFields();
List<String> cookies = headers.get("Set-Cookie");

if (cookies != null) {
for (String cookie : cookies) {
if (cookie.startsWith("JSESSIONID")) {
jsessionId = cookie.split(";")[0].split("=")[1];
break;
}
}
}

if (jsessionId == null) {
throw new RuntimeException(INVALID_SESSION);
}
} catch (URISyntaxException e) {
throw new RuntimeException(INVALID_URL);
}
}

private boolean attemptLogin(LoginReq loginReq) throws IOException {
try {
URI uri = new URI(SJ_LOGIN_URL);
URI uri = new URI(PORTAL_LOGIN_URL);
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection();
connection.setRequestMethod("POST");
connection.setRequestProperty("Cookie", "JSESSIONID=" + jsessionId);
connection.setRequestProperty("Referer", "https://portal.sejong.ac.kr/jsp/login/loginSSL.jsp");
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
connection.setDoOutput(true);

String postData = "userId=" + URLEncoder.encode(loginReq.getUserId(), StandardCharsets.UTF_8.toString()) +
"&password=" + URLEncoder.encode(loginReq.getPassword(), StandardCharsets.UTF_8.toString());
String postData = "mainLogin=Y" +
"&rtUrl=" + URLEncoder.encode("https://classic.sejong.ac.kr/classic/index.do", StandardCharsets.UTF_8.toString()) +
"&id=" + URLEncoder.encode(loginReq.getUserId(), StandardCharsets.UTF_8.toString()) +
"&password=" + URLEncoder.encode(loginReq.getPassword(), StandardCharsets.UTF_8.toString()) +
"&chkNos=on";

try (OutputStream os = connection.getOutputStream()) {
byte[] input = postData.getBytes(StandardCharsets.UTF_8);
os.write(input, 0, input.length);
}

int responseCode = connection.getResponseCode();
String responseMessage = readResponse(connection);
return responseCode == 302 && !responseMessage.contains(CONTAINS_HTML);
} catch (URISyntaxException e) {
throw new RuntimeException(INVALID_URL);
}
}
if (responseCode != 200) {
return false;
}

private String readResponse(HttpURLConnection connection) throws IOException {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()))) {
StringBuilder response = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
response.append(line);
String cookie = connection.getHeaderField("Set-Cookie");
if (cookie != null && cookie.contains("ssotoken=")) {
ssoToken = cookie.substring(cookie.indexOf("ssotoken=") + 9, cookie.indexOf(";", cookie.indexOf("ssotoken=")));
return true;
}
return response.toString();
return false;

} catch (URISyntaxException e) {
throw new RuntimeException(INVALID_URL);
}
}

public String getJsessionId() {
return jsessionId;
public String getSsoToken() {
return ssoToken;
}
}
28 changes: 11 additions & 17 deletions src/main/java/org/yj/sejongauth/domain/ProfileService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,21 @@
import java.net.URL;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.springframework.stereotype.Service;

public class ProfileService {
private final String PROFILE_URL = "http://classic.sejong.ac.kr/userCertStatus.do?menuInfoId=MAIN_02_05";
private final String FAIDED_PROFILE = "정보 조회에 실패하였습니다.";
private final String CLASSIC_URL = "https://classic.sejong.ac.kr/classic/reading/status.do";
private final String FAILED_PROFILE = "정보 조회에 실패하였습니다.";

public SjProfile fetchUserProfile(String jsessionId) {
public SjProfile fetchUserProfile(String ssoToken) {
try {
URL url = new URL(PROFILE_URL);
URL url = new URL(CLASSIC_URL);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setRequestMethod("GET");
connection.setRequestProperty("Cookie", "JSESSIONID=" + jsessionId);

connection.setRequestProperty("Cookie", "ssotoken=" + ssoToken);
Document doc = Jsoup.parse(readResponse(connection));
return parseProfileFromHtml(doc);
} catch (IOException e) {
throw new RuntimeException(FAIDED_PROFILE);
throw new RuntimeException(FAILED_PROFILE);
}
}

Expand All @@ -39,14 +37,10 @@ private String readResponse(HttpURLConnection connection) throws IOException {
}

private SjProfile parseProfileFromHtml(Document document) {
String major = document.select("div.contentWrap li dl dd").get(0).text();
String studentCode = document.select("div.contentWrap li dl dd").get(1).text();
String name = document.select("div.contentWrap li dl dd").get(2).text();
int gradeLevel = Integer.parseInt(document.select("div.contentWrap li dl dd").get(3).text().split(" ")[0]);
String userStatus = document.select("div.contentWrap li dl dd").get(4).text();
int completedSemesters = Integer.parseInt(document.select("div.contentWrap li dl dd").get(5).text().split(" ")[0]);
int verifiedSemesters = Integer.parseInt(document.select("div.contentWrap li dl dd").get(6).text().split(" ")[0]);
String major = document.select("th:contains(학과명) + td").text().trim();
String name = document.select("th:contains(이름) + td").text().trim();
String userStatus = document.select("th:contains(사용자 상태) + td").text().trim();

return new SjProfile(major, studentCode, name, gradeLevel, userStatus, completedSemesters, verifiedSemesters);
return new SjProfile(major, name, userStatus);
}
}
}
16 changes: 1 addition & 15 deletions src/main/java/org/yj/sejongauth/domain/SjProfile.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,16 @@

public class SjProfile {
private final String major;
private final String studentCode;
private final String name;
private final int gradeLevel;
private final String userStatus;
private final int completedSemesters;
private final int verifiedSemesters;

public SjProfile(String major, String studentCode, String name,
int gradeLevel, String userStatus,
int completedSemesters, int verifiedSemesters) {
public SjProfile(String major, String name, String userStatus) {
this.major = major;
this.studentCode = studentCode;
this.name = name;
this.gradeLevel = gradeLevel;
this.userStatus = userStatus;
this.completedSemesters = completedSemesters;
this.verifiedSemesters = verifiedSemesters;
}

public String getMajor() { return major; }
public String getStudentCode() { return studentCode; }
public String getName() { return name; }
public int getGradeLevel() { return gradeLevel; }
public String getUserStatus() { return userStatus; }
public int getCompletedSemesters() { return completedSemesters; }
public int getVerifiedSemesters() { return verifiedSemesters; }
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ void setUp() {
@Disabled
void testAuthenticate_Success() throws IOException {
// Given
authService.fetchJsessionId();

//when
boolean isAuthenticated = authService.authenticate("학번", "비번");
Expand Down

0 comments on commit 49e508c

Please sign in to comment.