본문 바로가기

STUDY/Spring

Spring | 스프링 시큐리티(Spring Security) (3) JDBC 로그인

이전 글에서는 in memory방식의 로그인, 이번 글에서는 DB연동 로그인을 해볼 것.

 

 

0. 간단한 회원가입 구현

0-1. 회원 정보를 저장할 DB table 생성

 

이 때 필수로 enabled컬럼을 작성해주어야 함. 스프링 시큐리티에서 요구하는 필수 요건?이며 0은 비활성화 상태, 1은 활성화 상태를 의미함. auth컬럼은 회원의 role을 저장할 곳. 따로 테이블을 생성해 join해서 가져와도 됨.

 

 

auth컬럼은 기본 값으로 'ROLE_USER'가 저장되도록 설정해주었음.

*insert시에 아무 값도 입력하지 않으면 자동으로 ROLE_USER값이 저장

 

--테이블 생성 쿼리문

CREATE TABLE USERS (
    ID VARCHAR2(50) NOT NULL PRIMARY KEY,
    PASSWORD VARCHAR2(200) NOT NULL,
    NAME VARCHAR2(200) NOT NULL UNIQUE,
    AUTH VARCHAR2(50) DEFAULT 'ROLE_USER' NOT NULL,
    ENABLED NUMBER(1) NOT NULL
);

 

 

0-2. UserDto, UserDao, UserService클래스 및 패키지 작성

 

① dto패키지 생성 - UserDto클래스 생성

② dao, service패키지 생성 - UserDao, UserService interface생성 - 각각 패키지 하위에 impl패키지 생성 - impl패키지 하위에 UserDaoImpl, UserServiceImpl클래스 작성(interface상속받기)

 

경로 참고

 

UserDto클래스 작성시 기본 생성자(빈 생성자) 꼭 작성할 것!

getter, setter, toString메서드 생성

*다른 클래스는 생략

 

package com.gaemi.wiw.dto;

import java.io.Serializable;

@SuppressWarnings("serial")
public class UserDto implements Serializable{
	
	private String id;
	private String password;
	private String name;
	private String auth;
	private int enabled;
	
	public UserDto() {
		
	}
	
	public UserDto(String id, String password, String name, String auth, int enabled) {
		super();
		this.id = id;
		this.password = password;
		this.name = name;
		this.auth = auth;
		this.enabled = enabled;
	}

	public String getId() {
		return id;
	}

	public void setId(String id) {
		this.id = id;
	}

	public String getPassword() {
		return password;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getAuth() {
		return auth;
	}

	public void setAuth(String auth) {
		this.auth = auth;
	}

	public int getEnabled() {
		return enabled;
	}

	public void setEnabled(int enabled) {
		this.enabled = enabled;
	}

	@Override
	public String toString() {
		return "UserDto [id=" + id + ", password=" + password + ", name=" + name + ", auth=" + auth + ", enabled="
				+ enabled + "]";
	}
	
}

 

 

0-3. MyBatis mapper작성

 

0-3-1. mybatis-config.xml파일에 alias등록(필수 아님)

 

더 편리한 사용을 위해 등록함.

type에 UserDto경로를 모두 입력 후 alias에 구분자/식별자를 등록.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration
    PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
    "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
	<typeAliases>
		<typeAlias alias="UserDto" type="com.gaemi.wiw.dto.UserDto" />
	</typeAliases>
</configuration>

 

 

0-3-2. Users.xml생성 및 작성

 

회원가입을 위한 INSERT문 작성. #{id}는 UserDto객체에 담겨온 id값!

parameterType에 config에서 등록한 alias값을 사용하면 자동으로 UserDto의 생성자와 매핑이 됨.

만약 config에 등록하지 않았다면 com.gaemi.wiw.dto.UserDto입력

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
  PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
  "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="Users">
	<insert id="register" parameterType="UserDto">
		INSERT INTO USERS(ID, PASSWORD, NAME, ENABLED) 
		VALUES( #{id} , #{password} , #{name} , 1 )
	</insert>
</mapper>

 

 

0-4. 회원가입 form작성

method는 post로 하며, csrf토큰 생성 필수(스프링 시큐리티를 사용하기 때문)

※controller로 넘어오는 input 값의 한글이 계속 깨진다면... web.xml의 필터 매핑 순서가 한글 인코딩 - 스프링시큐리티 인지 확인하기..^^...

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>

<h1>Register</h1>
<form action="${pageContext.request.contextPath}/users/registerAf" method="post">
	<div> id <input type="text" name="id" /> </div> 
	<div> pw <input type="password" name="password" /> </div> 
	<div> name <input type="text" name="name" /> </div> 
	<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" /> 
	<div> <input type="submit" value="회원가입"/> </div> 
</form>

</body>
</html>

 

 

0-5. 회원가입 form에서 입력받은 비밀번호 encoding하기!

이것이 바로 느닷없이 회원가입부터 만들어본 이유... DB에도 암호화된 비밀번호를 저장해놔야 DB를 통한 로그인이 됨!

 

0-5-1. UserServiceImpl에서 변환해주기

BCryptPasswordEncoder를 이용해 입력받은 비밀번호를 변환하여 객체에 담기.

당연히... 바로 setter해줘도 됩니다.......

 

package com.gaemi.wiw.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import com.gaemi.wiw.dao.UserDao;
import com.gaemi.wiw.dto.UserDto;
import com.gaemi.wiw.service.UserService;

@Service
public class UserServiceImpl implements UserService {

	@Autowired
	private UserDao userDao;
	
	@Autowired
	private BCryptPasswordEncoder bcryptPasswordEncoder;
	
	@Override
	public void RegisterUser(UserDto userInfo) {
				
		System.out.println("Befor Encoder : " + userInfo.getPassword());
		String endcodedPassword = bcryptPasswordEncoder.encode(userInfo.getPassword());
		System.out.println("After Encoder : " + endcodedPassword);
		System.out.println("Resister User Info : " + userInfo);
        
		userInfo.setPassword(endcodedPassword);	
		userDao.RegisterUser(userInfo);
		
	}

}

 

 

0-5-2. DB에 잘 저장됐나 확인(드디어)

 

짝짝짝

 

 

 

 

 

1. spring-security.xml파일 수정

 

bean등록

<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

 

username-parameter를 id로 변경(USERS테이블의 컬럼 명과 동일하게)

*필수 아님 쿼리문 작성시 as username으로 매칭시켜 줄 수 있음

 

session-management를 통해 한 개 이상의 세션이 생성되지 않도록 하며

세션이 더 생성되려고 할 경우 로그인 페이지로 이동하도록 설정

 

 

in memory방식의 로그인 설정 부분 주석처리, 위에서 등록한 bean을 이용해 password-encoder설정

jdbc-user-service를 이용해 DB를 이용한 로그인 설정

  • dataSource : root-context.xml에 등록된 bean
  • users-by-username-query : 존재하는 유저인지 확인. ID(username), PASSWORD, ENABLED컬럼 필요
  • authorities-by-username-query : 유저의 role확인

 

 

spring-security.xml 전체코드

더보기

 

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:security="http://www.springframework.org/schema/security"
	xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	
	<bean id="bcryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" />

	<security:http>
		<security:intercept-url pattern="/" access="permitAll"/>
		<security:intercept-url pattern="/users/member" access="hasRole('ROLE_MEMBER')"/>
		<security:intercept-url pattern="/users/admin" access="hasRole('ROLE_ADMIN')"/>
		<security:form-login login-page="/users/login"
							 username-parameter="id"
							 login-processing-url="/users/login-processing"
							 default-target-url="/" />
		
		
		<!-- 최대 한 개의 세션만 생성되도록 -->
		<security:session-management invalid-session-url="/users/login">
            <security:concurrency-control max-sessions="1"
            							  expired-url="/users/login"
            							  error-if-maximum-exceeded="true" />
        </security:session-management>
	</security:http>
	
	<security:authentication-manager>	
		<security:authentication-provider>			
			<!--  
			<security:user-service>		
				<security:user name="aaa" password="{noop}aaa" authorities="ROLE_MEMBER"/>
				<security:user name="admin" password="{noop}admin" authorities="ROLE_MEMBER, ROLE_ADMIN"/> 
			</security:user-service>
			-->	
			<security:password-encoder hash="bcrypt"/>
			<security:jdbc-user-service data-source-ref="dataSource"
				users-by-username-query="SELECT ID, PASSWORD, ENABLED FROM USERS WHERE ID=?"
				authorities-by-username-query="SELECT ID, PASSWORD, AUTH as authority FROM USERS WHERE ID=?"
			/>			
		</security:authentication-provider>
	</security:authentication-manager>

</beans>

 

 

2. 로그인 해보기(드!디!어!)

+) 참고

 

[Spring Security] 현재 로그인한 사용자 정보 가져오기

Spring Security 에서 현재 인증된(로그인한) 사용자의 정보를 가져오는 방법 에 대해 살펴볼 것 입니다. 스프링의 다양한 메카니즘을 통해 현재 로그인 중인 사용자의 정보를 가져올 수 있는데, 대��

itstory.tk

 

로그인 후 home으로 돌아가도록 설정해놨음