[Java] 로그인 - 일반 로그인

cowmin·2025년 7월 18일

1. 쿠키의 필요성

1.1 로그인 상태 유지를 위해

사용자가 로그인하면 JWT가 생성된다. 그걸 쿠키에 넣으면, 브라우저가 이후 요청마다 자동으로 쿠키를 전송한다. 즉, 로그인 이후 다른 페이지를 요청할 때도 서버가 사용자를 식별할 수 있게 되는 것이다.

1.2 보안상 안전하게 전달하기 위해

HttpOnly 속성을 사용하면 자바스크립트로 쿠키에 접근할 수 없다. 로컬스토리지나 세션스토리지에 JWT를 저장하는 방식보다 보안적으로 더 안전한 방식이다.

1.3 브라우저가 자동으로 보내줘서 편리함

프론트 코드 수정 없이도 자동으로 서버에 보내져서 인증 절차가 간편해진다.



2. 로그인 흐름

2.1 Controller

유저에게 email과 Password를 입력받는다.
반환받은 JWT가 null이 아니라면 쿠키를 생성한다.

2.2 Service

DB에 해당 유저가 존재하는지 확인한다.
반환받은 닉네임이 null이 아니라면 JWT를 생성한다.

2.3 Repository

DB에 해당 유저가 존재하는지 확인한다.
유저가 존재하면 해당 유저의 닉네임을 반환하고 존재하지 않으면 null을 반환한다.



3. LoginController

@WebServlet("/user/login")
public class LoginController extends HttpServlet {
    private final UserService userService = new UserService();
    
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        try {
            UserDto.Login dto = UserDto.Login.from(req);
            String jwt = userService.login(dto);

            if(jwt != null) {
                Cookie cookie = new Cookie("SJB_AT", jwt);
                cookie.setHttpOnly(true);
                resp.addCookie(cookie);

                // 응답에 jwt를 바로 줌 (보안 취약)
                //resp.getWriter().write(JsonParser.from(BaseResponse.success(jwt)));

                // 쿠키에 담아서 줌
                resp.getWriter().write(JsonParser.from(BaseResponse.success(cookie)));
            }
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }

    }
}


4. UserDto

public class UserDto {
    public static class Login {

        private String email;
        private String password;

        public static UserDto.Login from(HttpServletRequest req) throws IOException {
            ObjectMapper objectMapper = new ObjectMapper();
            UserDto.Login dto = objectMapper.readValue(req.getReader(), UserDto.Login.class);

            return dto;
        }

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}


5. UserService

public class UserService {
    private final UserRepository userRepository = new UserRepository();

    public String login(UserDto.Login dto) throws SQLException {
        String nickname = userRepository.findByEmailAndPassword(dto);

        if (nickname != null) {
            String jwt = JwtUtil.generateToken(dto.getEmail(), nickname);
            return jwt;
        }
        return null;
    }
}


6. UserRepository

public class UserRepository {
    public String findByEmailAndPassword(UserDto.Login dto) throws SQLException {
        Statement stmt = DBUtil.getStatement();
        ResultSet rs = stmt.executeQuery("SELECT * FROM user WHERE email='"+dto.getEmail()+"' AND password='"+dto.getPassword()+"'");
        if(rs.next()) {
            return rs.getString("nickname");
        } else {
            return null;
        }
    }
}


7. JwtUtil

package com.example.utils;

public class JwtUtil {
    private static final String SECRET = "abcdeffghijklmnopqrstuvwxyz0123456";
    private static final Key KEY = Keys.hmacShaKeyFor(SECRET.getBytes());
    private static final Long EXP = 1000 * 60 * 1L;

    public static String generateToken(String email, String nickname) {

        Map<String, String> claims =  new HashMap<>();
        claims.put("nickname", nickname);
        claims.put("role", "USER");

        return Jwts.builder()
                .setSubject(email)
                .setClaims(claims)
                .setExpiration(new Date(System.currentTimeMillis() + EXP))
                .signWith(KEY, SignatureAlgorithm.HS256)
                .compact();
    }

    public static String getRole(Claims claims) {
        String role = (String) claims.get("role");

        return role;
    }

    public static Claims getClaims(String token) {
        return Jwts.parserBuilder()
                .setSigningKey(KEY)
                .build()
                .parseClaimsJws(token)
                .getBody();
    }
}


8. 포스트맨 테스트 캡처

0개의 댓글