-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #1 from urinaner/develop
sejong-auth v1
- Loading branch information
Showing
10 changed files
with
423 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
# SejongAuth | ||
|
||
SejongAuth는 세종대학교 통합 로그인 페이지에 접근하여 사용자 인증과 프로필 정보를 가져오는 Java 기반의 패키지입니다. `Sj`를 통해 세종대학교 포털에 간편하게 로그인하고 사용자의 학적 정보를 조회할 수 있습니다. | ||
|
||
## 주요 기능 | ||
|
||
- **로그인 기능**: `LoginReq`를 사용하여 세종대학교 포털에 로그인하고 `JSESSIONID`를 획득합니다. | ||
- **프로필 조회 기능**: 로그인 성공 시 `ProfileService`를 통해 사용자의 학적 정보를 가져옵니다. | ||
|
||
--- | ||
|
||
## 설치 방법 | ||
|
||
gradle | ||
```properties | ||
dependencyResolutionManagement { | ||
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) | ||
repositories { | ||
mavenCentral() | ||
maven { url 'https://jitpack.io' } | ||
} | ||
} | ||
dependencies { | ||
implementation 'com.github.urinaner:sejong-auth:Tag' | ||
} | ||
``` | ||
maven | ||
```yaml | ||
<repositories> | ||
<repository> | ||
<id>jitpack.io</id> | ||
<url>https://jitpack.io</url> | ||
</repository> | ||
</repositories> | ||
|
||
<dependency> | ||
<groupId>com.github.urinaner</groupId> | ||
<artifactId>sejong-auth</artifactId> | ||
<version>Tag</version> | ||
</dependency> | ||
``` | ||
|
||
|
||
--- | ||
|
||
## 프로젝트 구조 | ||
|
||
``` | ||
SejongAuth/ | ||
├── src/ | ||
│ ├── main/ | ||
│ │ ├── java/org/yj/sejongauth/controller/Sj.java | ||
│ │ ├── java/org/yj/sejongauth/domain/AuthService.java | ||
│ │ ├── java/org/yj/sejongauth/domain/LoginReq.java | ||
│ │ ├── java/org/yj/sejongauth/domain/ProfileRes.java | ||
│ │ └── java/org/yj/sejongauth/domain/ProfileService.java | ||
│ └── test/ | ||
│ └── java/org/yj/sejongauth/controller/AuthControllerTest.java | ||
└── build.gradle | ||
``` | ||
|
||
--- | ||
|
||
## 사용법 | ||
|
||
### 1. `LoginRequestDto` 생성 | ||
|
||
로그인 요청 객체를 생성합니다. | ||
|
||
```java | ||
LoginRequestDto loginRequestDto = new LoginRequestDto("userId", "password"); | ||
``` | ||
|
||
### 2. 로그인 및 프로필 조회 | ||
|
||
`Sj.login()` 메서드를 사용하여 로그인 및 프로필 정보를 조회할 수 있습니다. | ||
|
||
```java | ||
ProfileRes profile = Sj.login(loginReq); | ||
System.out.println("User profile: " + profile); | ||
``` | ||
|
||
--- | ||
|
||
## 예제 | ||
|
||
아래는 `Sj.login` 메서드를 호출하여 간단히 로그인과 프로필 조회를 수행하는 예제입니다. | ||
|
||
```java | ||
|
||
public class Main { | ||
public static void main(String[] args) { | ||
LoginReq loginReq = new LoginReq("testUser", "testPassword"); | ||
|
||
try { | ||
ProfileRes profile = Sj.login(loginReq); | ||
System.out.println("Login successful. User profile: " + profile); | ||
} catch (RuntimeException e) { | ||
System.err.println("Login failed: " + e.getMessage()); | ||
} | ||
} | ||
} | ||
``` | ||
|
||
--- | ||
|
||
## 테스트 | ||
|
||
`AuthService` 클래스에서 로그인에 대한 테스트를 실행할 수 있습니다. | ||
|
||
|
||
--- | ||
|
||
## 주의사항 | ||
|
||
- **네트워크 연결**: 이 프로그램은 네트워크 연결이 필요합니다. | ||
- **예외 처리**: 네트워크 오류, 로그인 실패 등의 상황에서 `RuntimeException`이 발생할 수 있습니다. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
package org.yj.sejongauth.controller; | ||
|
||
import org.yj.sejongauth.domain.AuthService; | ||
import org.yj.sejongauth.domain.LoginReq; | ||
import org.yj.sejongauth.domain.ProfileRes; | ||
import org.yj.sejongauth.domain.ProfileService; | ||
|
||
public class Sj { | ||
|
||
private static final AuthService authService = new AuthService(); | ||
private static final ProfileService PROFILE_SERVICE = new ProfileService(); | ||
|
||
public static ProfileRes login(LoginReq loginReq) { | ||
if (authService.authenticate(loginReq)) { | ||
String jsessionId = authService.getJsessionId(); | ||
return PROFILE_SERVICE.fetchUserProfile(jsessionId); | ||
} else { | ||
throw new RuntimeException("인증에 실패하였습니다."); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
package org.yj.sejongauth.domain; | ||
|
||
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.util.List; | ||
import java.util.Map; | ||
|
||
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 final String INVALID_AUTH = "인증이 실패하였습니다."; | ||
private final String INVALID_SESSION = "SESSION_ID 가져오는 것을 실패하였습니다."; | ||
private final String INVALID_URL = "URL이 유효하지 않습니다."; | ||
private final String CONTAINS_HTML = "로그인 정보가 올바르지 않습니다."; | ||
|
||
public boolean authenticate(LoginReq loginReq) { | ||
try { | ||
fetchJsessionId(); | ||
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); | ||
HttpURLConnection connection = (HttpURLConnection) uri.toURL().openConnection(); | ||
connection.setRequestMethod("POST"); | ||
connection.setRequestProperty("Cookie", "JSESSIONID=" + jsessionId); | ||
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded"); | ||
connection.setDoOutput(true); | ||
|
||
String postData = "userId=" + loginReq.getUserId() + "&password=" + loginReq.getPassword(); | ||
try (OutputStream os = connection.getOutputStream()) { | ||
byte[] input = postData.getBytes("utf-8"); | ||
os.write(input, 0, input.length); | ||
} | ||
|
||
int responseCode = connection.getResponseCode(); | ||
System.out.println(responseCode); | ||
String responseMessage = readResponse(connection); | ||
System.out.println(responseMessage); | ||
return responseCode == 302 && !responseMessage.contains(CONTAINS_HTML); | ||
} catch (URISyntaxException e) { | ||
throw new RuntimeException(INVALID_URL); | ||
} | ||
} | ||
|
||
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); | ||
} | ||
return response.toString(); | ||
} | ||
} | ||
|
||
public String getJsessionId() { | ||
return jsessionId; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package org.yj.sejongauth.domain; | ||
|
||
public class LoginReq { | ||
private final String userId; | ||
private final String password; | ||
|
||
public LoginReq(String userId, String password) { | ||
this.userId = userId; | ||
this.password = password; | ||
} | ||
|
||
public String getUserId() { | ||
return userId; | ||
} | ||
|
||
public String getPassword() { | ||
return password; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package org.yj.sejongauth.domain; | ||
|
||
public class ProfileRes { | ||
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 ProfileRes(String major, String studentCode, String name, | ||
int gradeLevel, String userStatus, | ||
int completedSemesters, int verifiedSemesters) { | ||
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; } | ||
} |
51 changes: 51 additions & 0 deletions
51
src/main/java/org/yj/sejongauth/domain/ProfileService.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
package org.yj.sejongauth.domain; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.io.InputStreamReader; | ||
import java.net.HttpURLConnection; | ||
import java.net.URL; | ||
import org.jsoup.Jsoup; | ||
import org.jsoup.nodes.Document; | ||
|
||
public class ProfileService { | ||
private final String PROFILE_URL = "http://classic.sejong.ac.kr/userCertStatus.do?menuInfoId=MAIN_02_05"; | ||
private final String FAIDED_PROFILE = "정보 조회에 실패하였습니다."; | ||
|
||
public ProfileRes fetchUserProfile(String jsessionId) { | ||
try { | ||
URL url = new URL(PROFILE_URL); | ||
HttpURLConnection connection = (HttpURLConnection) url.openConnection(); | ||
connection.setRequestMethod("GET"); | ||
connection.setRequestProperty("Cookie", "JSESSIONID=" + jsessionId); | ||
|
||
Document doc = Jsoup.parse(readResponse(connection)); | ||
return parseProfileFromHtml(doc); | ||
} catch (IOException e) { | ||
throw new RuntimeException(FAIDED_PROFILE); | ||
} | ||
} | ||
|
||
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); | ||
} | ||
return response.toString(); | ||
} | ||
} | ||
|
||
private ProfileRes 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]); | ||
|
||
return new ProfileRes(major, studentCode, name, gradeLevel, userStatus, completedSemesters, verifiedSemesters); | ||
} | ||
} |
Oops, something went wrong.