Spring Security

스프링부트 스프링시큐리티 연동하기(1) Gradle/Mybatis/Oracle

dev.mk 2019. 6. 15. 23:27
반응형

스프링부트로 스프링시큐리티 연동하는 예제가 별로 없어서 포스팅을 하게 되었다. (일반 xml로 하는 연동과 별반 차이는 없다..)

개발 사양은 다음과 같다.

SpringBoot 버전 2.x / Gradle 버전 3.x / jdk 1.8 / Srping 버전 5.x  / Spring Security 버전 5.x / 오라클11g xe

나도 스프링 시큐리티를 잘 모르지만 복습차원에서 비교적 간단하게 스프링시큐리티를 구현하겠다.

1. 스프링부트 프로젝트를 Gradle 빌드 타입으로 생성한다.

2. 프로젝트가 생성되면 build.gradle파일에 필요한 dependencies를 추가해야 한다.

(build.gradle)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
repositories {
    mavenCentral()
    maven { url "https://code.lds.org/nexus/content/groups/main-repo"}  /* oracle ref url*/
}
 
dependencies {
 
    implementation 'org.projectlombok:lombok'
    compile group: 'org.springframework.security', name: 'spring-security-taglibs', version: '5.0.6.RELEASE'
    compile('javax.servlet:jstl')
    
    
    /*lombok*/
    implementation 'org.projectlombok:lombok'
    
    /*devtools*/
    
     /* oracle jdbc driver */
        
    /*mybais*/
    
    /* log */   
    
}
 

시큐리티 포스팅 작업에 필요한 dependencies가 모두 등록되있다.

등록 후 프로젝트 우클릭 > Gradle > Refresh Gradle Project

 

3. 부트는 설정파일이 src/main/resources/application.properties 경로에 파일이 생성된다. 이 프로퍼티에 

각종 설정 값을 선언해야 한다.

(application.properties)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# View
 
# sql log driver
 
# 데이터베이스 정보 입력
spring.datasource.username=devmk
spring.datasource.password=1234
 
# vo의 패키지 경로 
 
# 쿼리를 작성한 xml 의 경로
 
# devtools
spring.devtools.livereload.enabled=true
 
#Encoding UTF-8
 
#Messages
spring.messages.basename=messages/message

나는 위와 같이 설정을 하였다. 앞으로 이 설정 기준으로 디렉토리를 만들겠다.

나의 디렉토리 구조

4. 시큐리티 작업에 필요한 회원테이블을 생성한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
  CREATE TABLE "DEVMG"."SECURITY_MEMBER" 
   (    "ID" VARCHAR2(255 BYTE),  --아이디
    "PASSWORD" VARCHAR2(255 BYTE), --비밀번호
    "SEQ" NUMBER, -- 시퀀스
    "MEMBER_NAME" VARCHAR2(255 BYTE), --이름
    "USER_ROLE" NVARCHAR2(25), -- 권한
    "EMAIL" VARCHAR2(255 BYTE), -- 이메일
    "PASSWORD_LOCK" VARCHAR2(255 BYTE), -- 비밀번호 틀린 횟수
    "PASSWORD_CHG_DATE" VARCHAR2(16 BYTE), -- 비밀번호 변경일자
    "REG_DATE" VARCHAR2(16 BYTE), -- 등록일
    "MOD_DATE" VARCHAR2(16 BYTE), -- 수정일
    "STATUS" VARCHAR2(2 BYTE) -- 회원상태
   )

위와 같이 테이블을 생성했다.

권한 USER_ROLE 컬럼은 필수이다. 이곳에 시큐리티 권한값이 들어가게 된다. 

다른 스프링 시큐리티 포스팅에는 유저권한 테이블을 나눴지만 나는 회원테이블에 넣었다.

비밀번호가 틀릴 시 카운트를 누적해야 하기 때문에 PASSWORD_LOCK 컬럼을 만들었다.

1
2
3
4
5
6
Insert into DEVMG.SECURITY_MEMBER (
    ID,PASSWORD,SEQ,MEMBER_NAME,USER_ROLE,EMAIL,PASSWORD_LOCK,PASSWORD_CHG_DATE,REG_DATE,MOD_DATE,STATUS
values (
    'user','1234',null,'유저','ROLE_USER',null,'0',null,null,null,null
);

샘플데이터를 1건 넣어주자

5. lombok으로 회원 vo를 만들어 주자. (Member.java)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
 
 
 
 
import lombok.Data;
 
@Data
public class Member implements UserDetails {
 
    private static final long serialVersionUID = 1L;
    
    private String id;
    private String password;
    private String memberName;
    private String email;
    private String userRole;
    private int passwordLock;
    private String regDate;
    private String modDate;
    private String passwordChgDate;
    private String status;
    
    /*UserDetails 기본 상속 변수 */
    private Collection<extends GrantedAuthority> authorities;
    private boolean isEnabled = true;
    private String username;
    private boolean isCredentialsNonExpired = true;
    private boolean isAccountNonExpired = true;
    private boolean isAccountNonLocked = true;
 
}
 

스프링 시큐리티의 인증정보를 담기 위해선 스프링시큐리티에서 제공하는 UserDetails의 인터페이스를

상속받고 기본 vo를 반드시 정의해야지만 빨간줄이 사라진다;

+추가로 로그인할때 로그를 남기기 위하여 로그용 vo도 만들었다.

(LoginLog.java)

1
2
3
4
5
6
7
8
9
10
import lombok.Data;
 
@Data
public class LoginLog extends Member {
    private String loginIp;
    private String loginDate;
 
}r

6. SQL파일을 작성 한다. (login.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<?xml version="1.0" encoding="UTF-8"?>
 
 
 
     <select id="getSelectMeberInfo" parameterType="String" resultType="com.devmk.test.vo.Member">
        /* 회원정보조회 */
        SELECT 
            ID as id
            , ID as username
            , PASSWORD as password
            , MEMBER_NAME as memberName
            , USER_ROLE as userRole
        FROM SECURITY_MEMBER
           WHERE ID = #{id}
    </select>
    
    <update id="setUpdatePasswordLockCnt" parameterType="String">
         /*비밀번호 틀린 횟수 증가*/
         UPDATE SECURITY_MEMBER 
        SET
              PASSWORD_LOCK = NVL(PASSWORD_LOCK, 0) + 1
        WHERE
              id = #{id}
    </update>
 
    <update id="setUpdatePasswordLockCntReset" parameterType="String">
         /*비밀번호 틀린 횟수 초기화*/
         UPDATE SECURITY_MEMBER 
        SET
              PASSWORD_LOCK = 0
        WHERE
              id = #{id}
    </update>
 
    <insert id="setInsertLoginLog" parameterType="com.devmk.test.vo.LoginLog">
        /* 로그인 로그 */
        INSERT INTO SECURITY_MEMBER_LOG
            (
                SEQ /* 테이블 키 */
                , ID /* 아이디 */
                , LOGIN_IP /* 로그인 아이피 */
                , LOGIN_DATE /* 로그인 날짜 */
                , STATUS /*성공여부*/
            )
        VALUES
            (
                   SEQ_SECURITY.nextval
                , #{id}
                , #{loginIp}
                , TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')
                , #{status}
            )
    </insert>
    
</mapper>

위의 마이바티스 태그에서 mapper namespace=는 dao의 경로를 넣었고 resultType은 vo가 있는 패키지 경로를 넣어야 한다.

parameterType=은 아이디만 받기 때문에 String형으로 정의 하였다.

+ 추가로 회원가입을 위해 join.xml을 새로 만들고 SQL을 작성한다. (join.xml)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
<?xml version="1.0" encoding="UTF-8"?>
 
 
 
    <insert id="setInsertMember" parameterType="com.devmk.test.vo.Member">
        /*회원 가입*/
        INSERT INTO SECURITY_MEMBER
            (
                SEQ /* 테이블 키 */
                , ID /* 아이디 */
                , PASSWORD /* 비밀번호 */
                , MEMBER_NAME /* 이름 */
                , USER_ROLE /* 권한 */
                  , EMAIL /* 이메일 */ 
                , PASSWORD_LOCK /* 비밀번호 틀린 횟수 */
                , PASSWORD_CHG_DATE /* 비밀번호 변경일자 */
                , REG_DATE /* 등록일 */
                , MOD_DATE /* 수정일 */
                , STATUS /* 회원상태 */
            )
        VALUES
            (
                SEQ_SECURITY.nextval
                , #{id}
                , #{password}
                , #{memberName}
                , #{userRole}
                , #{email}
                , 0
                , TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')
                , TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')
                , TO_CHAR(SYSDATE,'YYYYMMDDHH24MISS')
                , 'O'
            )
    </insert>
 
</mapper>

7. Dao를 만들어준다. (Mapper라고도 한다;)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 
 
 
 
@Mapper
public interface LoginMapper{
 
    //메소드 앞에 public 생략해도 기본적으로 public가 붙는다.
    
    /* 회원정보조회 */
    Member getSelectMeberInfo(String id);
    /* 회원가입 */
    public int setInsertMember(Member member);
    /* 로그인 로그 */
    public int setInsertLoginLog(LoginLog loginLog);
    /* 비밀번호 틀린 횟수 증 */
    public int setUpdatePasswordLockCnt(String id);
    /* 비밀번호 틀린횟수 초기화 */
    public int setUpdatePasswordLockCntReset(String id);
     
}
 

이 Dao안에 로그인에 필요한 CRUD를 넣으면 된다. 회원정보가 조회되어야 하기 때문에 리턴타입은 Member vo다.

이번 포스팅은 기본적인 프로젝트 셋팅, 테이블 생성 , VO, DAO를 작성하였다.

다음 포스팅은 스프링시큐리티에서 제공하는  UserDetailsService 인터페이스를 상속받아서 실제 인증하는 작업을 해보겠다~

 

반응형