I T H

[프로젝트] 10. 로그인 구현 (Week 3) 본문

Spring ArtGallery Project

[프로젝트] 10. 로그인 구현 (Week 3)

thdev 2024. 1. 23. 10:56

Spring Security를 사용한 로그인 구현 (커스터마이징)

 

로그인 로직을 개발 시 고려해야 할 로직은 아래와 같음.

로그인 성공 / 실패를 구분하여 처리
로그인 시 권한 정보를 부여하여 로그인 성공 시 권한에 따라 페이지 이동이 다르게 가도록 처리
로그인 실패에 대한 예외 처리 

 

- 스프링 시큐리티 소스코드나 이론에 대한 내용은 MyPortfolio Project에 시큐리티 관련 소스코드를 올려놓겠다.

 

[ 로그인 페이지 - login.jsp ]

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
	
<!DOCTYPE html>
<html lang="kr">

<head>
    <meta charset="UTF-8">
    <meta name="description" content="">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- The above 4 meta tags *must* come first in the head; any other head content must come *after* these tags -->

    <!-- Title  -->
    <title>ART - 로그인</title>

	<!-- import CSS -->
	<%@include file="/resources/inc/incCss.jsp"%>
</head>

<body>

    <!-- ##### Main Content Wrapper Start ##### -->
    <div class="main-content-wrapper d-flex clearfix">

        <!-- import Header -->
		<%@include file="/resources/inc/incHeader.jsp"%>

        <div class="cart-table-area section-padding-100">
            <div class="container-fluid">
                <div class="row">
                	<div class="col-3 col-lg-3">
                		&nbsp;
                	</div>
                    <div class="col-12 col-lg-6">
                        <div class="checkout_details_area mt-100 clearfix">

                            <div class="cart-title">
                                <h2>로그인</h2>
                            </div>

                            <form id="loginForm" method="POST" action="${loginUrl}">
                                <div class="row">
                                    <div class="col-md-12 mb-3">
                                    	<small>아이디</small>
                                        <input type="text" class="form-control" id="username" name="username" value="" placeholder="아이디 입력" required>
                                    </div>
                                    <div class="col-md-12 mb-3">
                                    	<small>비밀번호</small>
                                        <input type="password" class="form-control" id="password"  name="password" value="" placeholder="비밀번호 입력" required>
                                    	<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
                                    </div>
                                    <div class="col-md-6 mb-3" style="color: red;">
                                    	<c:if test="${not empty error}">	
											${error}
										</c:if>
                                    </div>
                                    <div class="col-md-6 mb-3">
                                    	<div class="cart-btn mt-50">
			                                <a id="btnSubmit" href="javascript:void(0)" class="btn amado-btn w-100">로그인</a>
			                            </div>
                                    </div>
                                </div>
                            </form>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <!-- ##### Main Content Wrapper End ##### -->

    <!-- import Footer -->
	<%@include file="/resources/inc/incFooter.jsp"%>

    <!-- import JS -->
	<%@include file="/resources/inc/incJs.jsp"%>
	
	<!-- page script -->
	<script src="/resources/views/login.js"></script>

</body>

</html>

 

[ login.js ]

/*******************************************************************************
 * 
 * login.js
 * 
 * @author thkim
 * @since 2022
 * @DESC 로그인용 스크립트
 * 
 ******************************************************************************/
(function() {
	
	function Login() {
		
		/* 
		 * private variables
		 */
		
		/* 
		 * 초기화 메소드
		 */
		function _init() {
			
			// 이벤트 바인딩
			bindEvent();
			
		}
		
		function bindEvent() {
			
			// 아이디 포커스 처리
			$("#username").focus();
			
			$("#username").keydown(function(key) {
				if (key.keyCode == 13) {
					login();
				}
			});
			$("#password").keydown(function(key) {
				if (key.keyCode == 13) {
					login();
				}
			});
			
			// 로그인 버튼 클릭 이벤트
			$("#btnSubmit").on("click", function() {
				login();
			});
		}
		
		function login() {
			if($("#username").val() == "") {
				alert("아이디를 입력하시기 바랍니다.");
				return false;
			}
			if($("#password").val() == "") {
				alert("비밀번호를 입력하시기 바랍니다.");
				return false;
			}
			
			$("#loginForm").submit();
		}
		
		function _finalize() {
		}
		
		return {
            init : _init,
            finalize : _finalize
        };
    };
    
    var login = new Login();
    login.init();
    
})();

//# sourceURL=login.js

 

[ UserAuthDAO ]

package kr.co.art.sys.security.authentication;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.*;
 
import javax.sql.DataSource;
 
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.*;

import kr.co.art.sys.security.userDetails.CustomUserInfo;
 
@Component
public class UserAuthDAO
{
    private Connection conn;
    private PreparedStatement pstmt;
    private ResultSet rs;
     
    @Autowired
    private DataSource dataSource;
     
    private Connection getConn()
    {
       try{
         conn = dataSource.getConnection();
         return conn;
       }catch(Exception e){
           e.printStackTrace();
           if(conn!=null){
                try {
                    conn.close();
                } catch (SQLException sqle){
                    sqle.printStackTrace();
                }
           }
       }
       return null;
    }
     
    private void closeAll() {
        try{
            if(rs!=null) rs.close();
            if(pstmt!=null) pstmt.close();
            if(conn!=null) conn.close();
        }catch(SQLException sqle){
            sqle.printStackTrace();
        }
    }
 
    public CustomUserInfo getUserDetails(String userId){
        conn  = getConn();
        String sql = "SELECT USER_ID\n"
        		+ "     , USER_PW\n"
        		+ "     , USER_NAME\n"
        		+ "     , AUTH_TYPE \n"
        		+ "     , OUT_YN \n"
        		+ "  FROM ART_USER\n"
        		+ " WHERE USER_ID = ?";
        try {
            pstmt = conn.prepareStatement(sql);
            pstmt.setString(1, userId);
            rs = pstmt.executeQuery();
            if(rs.next()){
                 
                String id = rs.getString("USER_ID");
                String pwd = rs.getString("USER_PW");
                String name = rs.getString("USER_NAME");
                String authType = rs.getString("AUTH_TYPE");
                String outYn = rs.getString("OUT_YN");
                String role = authType.equals("1") ? "USER_ROLE" : "ADMIN_ROLE"; // USER_ROLE : 일반사용자 / ADMIN_ROLE : 관리자 
                // 해당 role명이 applicationContext-security xml 파일에서 화면마다 권한 부여 시 사용될 권한이름이다.
                 
                List<GrantedAuthority> roles = new ArrayList<>();
                roles.add(new SimpleGrantedAuthority(role));
                
                CustomUserInfo customUserInfo = new CustomUserInfo(id, pwd, name, authType, outYn,  roles);
                return customUserInfo;
            }
        } catch (SQLException e) {
            e.printStackTrace();
        } finally{
            closeAll();
        }
         
        return null;
    }
}