728x90
들어가며
GitHub 클론 프로젝트에서는 복잡한 OAuth 나 소셜 로그인 없이, 기본적인 회원 관리 + 로그인/로그아웃 흐름만을 구현했습니다.
최초에는 세션 기반 로그인을 적용하고, 이후 구조 확장을 고려해 Spring Security 기반 처리로 전환했습니다.
간단한 흐름 요약
- 사용자 회원가입
- `Member` 엔티티를 DB에 저장
- 비밀번호는 `BCrypt` 를 사용해 해시 처리 후 저장
- 로그인 시 사용자 정보 조회
- `BCrypt` 의 `matches()` 활용하여 비밀번호 일치 여부 확인
- Session 기반 로그인
- 사용자 정보 세션 저장
- Spring Security 적용
- 세션 직접 조작 대신 로그아웃 처리만 유지
회원 기능 구현
DB ERD Diagram
회원 기능 패키지/클래스 생성
src
└── main
├── java
│ └── com.example
│ ├── core
│ └── javastudy
│ └── member
│ ├──model
│ ├──controller
│ └──service
├── resources
│ ├── mybatis
│ ├── static
│ └── application.yml
└──webapp
└── WEB-INF
├── tiles
└── views
- `com.example.javastudy` 하위에 `member` 패키지 생성
- 회원 도메인과 관련된 기능을 관리
- 기능별로 응집된 구조를 유지할 수 있도록 설계
- `member.model.MemberDto` 클래스 생성
- DB 컬럼을 기반으로 필드 정의
- `member.controller.MemberController` 클래스 생성
- `/member` 로 시작하는 URL 매핑 및 요청/응답 처리
- `member.service` 패키지에 `MemberService` 클래스와 `MemberMapper` 클래스 생성
- `Service` 클래스 : 비즈니스 로직 처리
- `Mapper` 클래스 : DB 접근
회원 CRUD 구현
// Controller
@PostMapping("/add")
public @ResponseBody AjaxResBody add(@RequestBody MemberDto memberDto) {
boolean result = false;
String message = "비정상 처리되었습니다.";
try {
result = memberService.insertMember(memberDto);
message = "정상 처리되었습니다.";
} catch (Exception e) {
e.printStackTrace();
}
return AjaxResBody.toResponse(result, message);
}
// Service
public boolean insertMember(MemberDto memberDto) {
memberDto.generateSeq();
memberDto.setMemberPassword(passwordEncoder.encode(memberDto.getMemberPassword()));
memberMapper.insertMember(memberDto.toEntity());
return true;
}
// Mapper
void insertMember(MemberVo entity);
- Controller 단 : `POST /member/add` 요청을 통해 회원가입 처리
- Service 단 : 외부 요청/응답용 `MemberDto` 를 내부 도메인 객체 (Entity) 로 변환
- `ULID` 를 이용해 PK 값인 `SEQ` 생성
- `MemberDto` 의 `memberPassword` 필드에 담긴 비밀번호 값을 `BCrypt` 를 이용해 암호화
- Mapper 단 : 내부 도메인 객체를 DB 에 저장
회원가입 (insert) 로직을 기준으로 설명하며, 나머지 조회/수정/삭제 등 CRUD 전체 코드는 아래 GitHub 링크에서 확인하실 수 있습니다.
member.service.MemberService.java
Session 기반 로그인 기능
// model
public class AuthDto {
private String memberId;
private String memberPassword;
}
// Service
public boolean processLogin(AuthDto authDto) {
MemberDto memberDto = memberService.selectMemberById(authDto.getMemberId());
if (memberDto == null) return false;
if (!isMatchPassword(authDto.getMemberPassword(), memberDto.getMemberPassword())) return false;
HttpSession session = CommonUtils.getSession();
session.setAttribute("loginMember", memberDto);
return true;
}
private boolean isMatchPassword(String rawPwd, String encodedPwd) {
return passwordEncoder.matches(rawPwd, encodedPwd);
}
- Controller 단 : `POST /auth/login` 요청을 통해 사용자 인증 처리
- Service 단 : 사용자 인증 성공 시 `HttpSession` 에 사용자 객체 저장
- 로그인 요청용 `AuthDto` 의 `memberId` 필드 값을 이용해 일치하는 회원 정보 검색
- 만약 일치하는 회원이 없으면 로그인 실패 처리
- 조회된 회원 정보의 `memberPassword` 필드와 로그인 요청용 `AuthDto` 의 `memberPassword` 필드 비교
- DB 에서 조회된 회원 정보의 비밀번호는 `BCrypt` 암호화되어있으므로 단순한 `equals()` 로는 비교 불가
- `BCrypt` 의 `matches()` 를 이용하여 암호문과 평문이 일치하는지 비교
- 비밀번호 일치할 경우 `HttpSession` 에 조회된 회원정보를 로그인 사용자로 저장
- 로그인 요청용 `AuthDto` 의 `memberId` 필드 값을 이용해 일치하는 회원 정보 검색
// Service
public void processLogout() {
HttpSession session = CommonUtils.getSession();
session.invalidate();
}
- Controller 단 : `GET /auth/logout` 요청을 통해 로그아웃 처리
- Service 단 : `HttpSession` 무효화 처리를 통해 저장된 로그인 정보 제거
Spring Security 적용
로그인 흐름
// Service
public boolean processLogin(AuthDto authDto) {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(authDto.getMemberId(), authDto.getMemberPassword());
Authentication auth = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(auth);
return true;
}
- Controller 단 : `POST /auth/login` 요청을 통해 사용자 인증 처리
- Service 단 : `AuthenticationManager` 를 통해 사용자 인증을 수행
- 인증에 성공하면 `SecurityContextHolder` 에 인증 객체를 저장하여 로그인 상태를 유지
(사용자 정보는 UserDetails 형태로 처리되지만, 본문에서는 인증 흐름 중심으로 설명을 제한합니다.)
- 인증에 성공하면 `SecurityContextHolder` 에 인증 객체를 저장하여 로그인 상태를 유지
SecurityConfig 설정 요약
@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Bean
public SecurityFilterChain httpSecurity(HttpSecurity http) throws Exception {
http.formLogin().disable();
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
http.httpBasic().disable();
http.logout()
.logoutUrl("/auth/logout")
.logoutSuccessUrl("/")
.invalidateHttpSession(true)
.clearAuthentication(true)
;
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/auth/**").permitAll()
.anyRequest().authenticated()
;
return http.build();
}
- 기본 인증 방식 (formLogin, httpBasic, CSRF) 을 모두 비활성화
- iframe 사용을 위해 동일 출처(sameOrigin) 허용
- 로그아웃 URL 호출 시 세션 무효화 및 인증 정보 제거
- 루트 페이지(/)와 인증 요청(/auth/**)은 누구나 접근 가능
- 그 외 모든 요청은 인증된 사용자만 접근 가능
실제 보안이 중요한 프로젝트라면 추가적인 인증/인가 설정이 필요하지만, 이 프로젝트에서는 개발 흐름에 집중할 수 있도록 복잡한 인가/권한 처리는 생략하고, 단순 로그인/로그아웃 및 인증 상태 유지에 필요한 설정만 구성했습니다.
다음 글에서는 GitHub의 핵심 기능 중 하나인 Repository 생성 및 브랜치/커밋 모델링 구조에 대해 소개하겠습니다.
관련 커밋
728x90
'Java | Spring > GitHub Clone Project' 카테고리의 다른 글
[GitHub Clone] 06. 커밋 그래프 시각화 (Mermaid.js vs GitGraph.js) (1) | 2025.04.18 |
---|---|
[GitHub Clone] 05. 커밋 / 머지 / 리베이스 기능 구현 (1) | 2025.04.17 |
[GitHub Clone] 04. 그룹 / 프로젝트 / 브랜치 도메인 설계 및 CRUD 구현 (1) | 2025.04.14 |
[GitHub Clone] 02. 프로젝트 구조 및 초기 설정 (2) | 2025.04.09 |
[GitHub Clone] 01. 프로젝트 소개 및 기술 스택 정리 (0) | 2025.04.07 |