Web Project/ems
login
hmmmmmmmmmmmm
2024. 8. 13. 21:05
AuthController.java
package net.javaguides.ems.controller;
import lombok.AllArgsConstructor;
import net.javaguides.ems.dto.JwtAuthResponse;
import net.javaguides.ems.dto.LoginDto;
import net.javaguides.ems.service.AuthService;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
@CrossOrigin("*")
@AllArgsConstructor
@RestController
@RequestMapping("/api/auth")
public class AuthController {
private AuthService authService;
// 로그인 API
@PostMapping("/login")
public ResponseEntity<JwtAuthResponse> login(@RequestBody LoginDto loginDto) {
JwtAuthResponse jwtAuthResponse = authService.login(loginDto);
return new ResponseEntity<>(jwtAuthResponse, HttpStatus.OK);
}
}
로그인 인증 처리
AuthService.java
package net.javaguides.ems.service;
import net.javaguides.ems.dto.JwtAuthResponse;
import net.javaguides.ems.dto.LoginDto;
public interface AuthService {
JwtAuthResponse login(LoginDto loginDto);
}
로그인 메소드 정의
AuthServiceImpl.java
package net.javaguides.ems.service.impl;
import lombok.AllArgsConstructor;
import net.javaguides.ems.dto.JwtAuthResponse;
import net.javaguides.ems.dto.LoginDto;
import net.javaguides.ems.entity.User;
import net.javaguides.ems.repository.UserRepository;
import net.javaguides.ems.security.JwtTokenProvider;
import net.javaguides.ems.service.AuthService;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.Optional;
@Service
@AllArgsConstructor
@Override
public JwtAuthResponse login(LoginDto loginDto) {
// 1. 사용자 인증
// authenticationManager로 사용자 인증 처리 (사용자이름이나 이메일, 비밀번호로 인증 시도)
// 인증 성공 시 authentication 변수에 사용자 정보 할당
Authentication authentication = authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(
loginDto.getUsernameOrEmail(),
loginDto.getPassword()
));
// 2. 인증된 사용자 정보를 세션에 저장
// 인증된 사용자 정보를 SecurityContextHolder에 할당해 세션 유지
SecurityContextHolder.getContext().setAuthentication(authentication);
// 3. jwt 토큰 생성
// 인증된 사용자 정보로 jwt 토큰 생성
String token = jwtTokenProvider.generateToken(authentication);
// 4. 사용자 정보 조회/역할 확인
// Optional<User>: 존재하지 않을 수도 있는 데이터 안전 처리
// userOptional: id, name, username, email, password, role
// 같은 파라미터(loginDto.getUsernameOrEmail()) 2번 전달하는 이유: 메소드가 username이든 email이든 상관없이 사용자 정보를 찾도록
// 사용자 이름이나 이메일로 사용자 조회 (role 추가 목적)
Optional<User> userOptional = userRepository.findByUsernameOrEmail(loginDto.getUsernameOrEmail(), loginDto.getUsernameOrEmail());
String role = null;
// 사용자가 있으면
if (userOptional.isPresent()) {
User loggedInUser = userOptional.get();
// 역할 중에 첫 번째 역할 가져오기
Optional<Role> optionalRole = loggedInUser.getRoles().stream().findFirst();
if (optionalRole.isPresent()) {
Role userRole = optionalRole.get();
// role 이름(ex: ROLE_USER, ROLE_ADMIN) 가져오기
role = userRole.getName();
}
}
// 5. JwtAuthResponse에 정보(tokentype, role) 설정
// jwtAuthResponse: 인증 후 클라이언트에게 전달하는 jwt와 토큰 정보 객체 (accessToken, tokenType, role)
JwtAuthResponse jwtAuthResponse = new JwtAuthResponse();
// accessToken은 이미 할당되어서 tokenType, role만 생성해서 할당
jwtAuthResponse.setRole(role);
jwtAuthResponse.setAccessToken(token);
// 6. jwt + 역할 정보 할당된 응답 반환
return jwtAuthResponse;
}
로그인 요청 처리
jwt 생성, 반환
LoginDto.java
package net.javaguides.ems.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class LoginDto {
private String usernameOrEmail;
private String password;
}
로그인 시 사용자가 입력하는 사용자 정보
JwtAuthResponse.java
package net.javaguides.ems.dto;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
public class JwtAuthResponse {
private String accessToken;
private String tokenType = "Bearer";
private String role;
}
로그인 후 서버가 클라이언트에게 반환하는 jwt 토큰 관련 정보
사용자가 인증되었고 세션이 유지되고 있다는 확인증 같은 것
JwtTokenProvider.java
package net.javaguides.ems.security;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.io.Decoders;
import io.jsonwebtoken.security.Keys;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;
import java.security.Key;
import java.util.Date;
@Component
public class JwtTokenProvider {
// jwt 비밀키
@Value("${app.jwt-secret}")
private String jwtSecret;
// jwt 유효기간
@Value("${app.jwt-expiration-milliseconds}")
private Long jwtExpirationMillis;
// 1. jwt 생성
public String generateToken(Authentication authentication) {
String username = authentication.getName();
Date currentDate = new Date();
Date expireDate = new Date(currentDate.getTime() + jwtExpirationMillis);
// jwt 생성 (username, 발행일, 만료일, 서명 포함)
String token = Jwts.builder()
.setSubject(username)
.setIssuedAt(new Date())
.setExpiration(expireDate)
.signWith(key())
.compact();
return token;
}
// 2. 서명에 사용할 비밀 키 생성
private Key key() {
return Keys.hmacShaKeyFor(
Decoders.BASE64.decode(jwtSecret)
);
}
// 3. jwt에서 username 가져오기 (인증된 사용자가 누구인지 확인)
public String getUsername(String token) {
Claims claims = Jwts.parser()
.setSigningKey(key())
.build()
.parseClaimsJws(token)
.getBody();
String username = claims.getSubject();
return username;
}
// 4. jwt 유효성 검증 (토큰이 변조되거나, 만료되지 않았는지 확인)
public boolean validateToken(String token) {
Jwts.parser()
.setSigningKey(key())
.build()
.parse(token);
// 예외가 발생하지 않으면 토큰이 유효함을 반환
return true;
}
}
jwt 토큰 생성
검증
토큰에서 사용자 정보 추출
UserRepository.java
package net.javaguides.ems.repository;
import net.javaguides.ems.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
public interface UserRepository extends JpaRepository<User, Long> {
Optional<User> findByUsernameOrEmail(String username, String email);
}
데이터베이스 User 스키마와 상호작용