Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
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
Tags
more
Archives
Today
Total
관리 메뉴

DOing

[Spring Security] DB를 이용하여 로그인 본문

Spring

[Spring Security] DB를 이용하여 로그인

mangdo 2021. 4. 28. 17:10

이전 포스팅에서는 특정한 계정에 대해서 로그인 처리를 하였다. 이번 포스팅에서는 좀 더 현실적으로 DB를 이용하는 방식을 이용해보자. 

 

1. root-context.xml 확인

dataSource라는 빈이 제대로 지정되어 있는 확인한다.

<bean id ="dataSource" class = "com.zaxxer.hikari.HikariDataSource" destroy-method="close">
	<constructor-arg ref ="hikariConfig"/>
</bean>

<bean id = "hikariConfig" class = "com.zaxxer.hikari.HikariConfig">

  <property name ="driverClassName" value="net.sf.log4jdbc.sql.jdbcapi.DriverSpy"></property>
  <property name ="jdbcUrl" value = "jdbc:log4jdbc:oracle:thin:@localhost:1521:xe"></property>
  <property name="username" value="BOOK"></property>
  <property name="password" value="BOOK"></property>	
  
</bean>

 

 

2. 테이블 생성

 

3. security-context.xml 수정

<security:authentication-manager>
	<security:authentication-provider>
    
		<security:jdbc-user-service data-source-ref="dataSource"/>
    
	</security:authentication-provider>
</security:authentication-manager>

 

4. PasswordEncoder

 스프링 시큐리티 5부터는 PasswordEncoder를 지정해야한다. 이전 포스팅에서는 임시로 {noop}을 사용해서 진행했지만 데이터 베이스를 이용하는 경우에는 PasswordEncoder를 사용해야 한다.

PasswordEncoder는 패스워드를 암호화 시킨다. 암호화되지 않은 실제 패스워드를 저장하거나 사용하는 일은 위험하다. 때문에 암호화된 패스워드로 저장하고, 사용자가 패스워드를 입력하면 이를 암호화해서 저장된 암호화된 비밀번호와 비교한다.

PasswordEncoder가 패스워드를 암호화하고 AuthenticationProvider가 암호화된 패스워드와 DB에 저장된 패스워드를 비교한다.(DB에도 암호화된 패스워드가 있다)

 

 PasswordEncoder는 인터페이스로 설계되어 있고 여러 종류의 구현 클래스가 존재한다. 그 중에서 BCyptPasswordEncoder를 사용해서 패스워드를 암호화해서 처리하자. BCyptPasswordEncoder는 패스워드를 저장하는 용도로 설계되었다. 해시 함수로 특정 문자열을 암호화하기 때문에 암호화를 한 후에, 다시 원문으로 돌리지 못한다.

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

<security:authentication-manager>
	<security:authentication-provider>
    
		<security:jdbc-user-service data-source-ref="dataSource"/>
        
		<security:password-encoder ref="bcryptPasswordEncoder"/>
        
	</security:authentication-provider>
</security:authentication-manager>

 

5. 암호화된 패스워드를 가지는 유저 추가

데이터베이스에도 BCyptPasswordEncoder로 암호화된 패스워드가 저장되어야한다. 아직 회원가입 기능을 구현하지 않은 상태이기 때문에 테스트 코드를 사용해서 유저를 추가한다.

 

[ Membertest.java ]

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({
  "file:src/main/webapp/WEB-INF/spring/root-context.xml",
  "file:src/main/webapp/WEB-INF/spring/security-context.xml"})
public class MemberTests {

  @Setter(onMethod_ = @Autowired)
  private PasswordEncoder pwencoder;
  
  @Setter(onMethod_ = @Autowired)
  private DataSource ds;
  
  // 유저 추가
  @Test
  public void testInsertMember() {

    String sql = "insert into tbl_member(userid, userpw, username) values (?,?,?)";
    
    for(int i = 0; i < 10; i++) {
      
      Connection con = null;
      PreparedStatement pstmt = null;
      
      try {
        con = ds.getConnection();
        pstmt = con.prepareStatement(sql);
        
        pstmt.setString(2, pwencoder.encode("pw" + i));
        
        if(i <8) {
          
          pstmt.setString(1, "user"+i);
          pstmt.setString(3,"사용자"+i);
          
        }else if (i <9) {
          
          pstmt.setString(1, "manager"+i);
          pstmt.setString(3,"매니저"+i);
          
        }else {
          
          pstmt.setString(1, "admin"+i);
          pstmt.setString(3,"관리자"+i);
          
        }
        
        pstmt.executeUpdate();
        
      }catch(Exception e) {
        e.printStackTrace();
      }finally {
        if(pstmt != null) { try { pstmt.close();  } catch(Exception e) {} }
        if(con != null) { try { con.close();  } catch(Exception e) {} }
        
      }
    }
  }
  
  // 권한 추가
  @Test
  public void testInsertAuth() {
    
    
    String sql = "insert into tbl_member_auth (userid, auth) values (?,?)";
    
    for(int i = 0; i < 10; i++) {
      
      Connection con = null;
      PreparedStatement pstmt = null;
      
      try {
        con = ds.getConnection();
        pstmt = con.prepareStatement(sql);
      
        
        if(i <8) {
          
          pstmt.setString(1, "user"+i);
          pstmt.setString(2,"ROLE_USER");
          
        }else if (i <9) {
          
          pstmt.setString(1, "manager"+i);
          pstmt.setString(2,"ROLE_MEMBER");
          
        }else {
          
          pstmt.setString(1, "admin"+i);
          pstmt.setString(2,"ROLE_ADMIN");
          
        }
        
        pstmt.executeUpdate();
        
      }catch(Exception e) {
        e.printStackTrace();
      }finally {
        if(pstmt != null) { try { pstmt.close();  } catch(Exception e) {} }
        if(con != null) { try { con.close();  } catch(Exception e) {} }
        
      }
    }//end for
  } 
}

 

 

6. 쿼리를 사용하는 인증

spring security에서 기본 제공하는 유저와 권한 테이블이 아닌 직접 테이블을 만들어서 사용하는 경우에는 인증을 위한 쿼리권한을 확인하는 쿼리가 필요하다. 인증을 위한 쿼리는 users-by-username-query로, 권한을 확인하는 쿼리는 authorities-by-username-query로 지정한다.

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

<security:authentication-manager>
	<security:authentication-provider>
    
		<security:jdbc-user-service data-source-ref="dataSource"/>
		<security:jdbc-user-service data-source-ref="dataSource"
				users-by-username-query="select userid, userpw, enabled from tbl_member where userid=?"
				authorities-by-username-query="select userid, auth from tbl_member_auth where userid=?"/>
		<security:password-encoder ref="bcryptPasswordEncoder"/>
        
	</security:authentication-provider>
</security:authentication-manager>