본문 바로가기

컴퓨터학원(복습)(수료)

자바(JAVA)기반 안드로이드 웹&앱 개발 80일차 스프링, MySQL (JDBC 이용 인증/권한 처리, 기존테이블 이용 인증/권한 처리, UserDetailsService)

[JDBC 를 이용하는 간편 인증/권한 처리]

현실적으로는 DB에 회원정보를 이용해서 로그인 처리를 합니다.

패스워드는 PasswordEncoder를 지정해서 처리합니다.

[JDBC를 이용하기 위한 테이블 설정]

1. 먼저 users 테이블을 만듭니다. 유저의 username(id) 와 password 를 저장하는 테이블입니다.

1) enabled 는 사용자를 사용 못하게 막는 용도입니다.

create table users (

username varchar(50) not null primary key,

password varchar(50) not null,

enabled char(1) default '1'

);

2. 그 후, authorities 테이블을 만듭니다. username 에 따른 권한(authority)를 저장하는 테이블입니다.

users 테이블의 username을 외래키(foreign key)로 갖고 있습니다.

create table authorities (

username varchar(50) not null,

authority varchar(50) not null,

constraint fk_authorities_users foreign key(username) references users(username)

);

3. authroties 테이블에 index 를 생성합니다.

1) 검색을 빠르게 해주기 위해서 생성한 것입니다.

create unique index ix_auth_username on authorities (username, authority);

4. 데이터를 넣어줍니다.

insert into users(username, password) values ('user00', 'pw00');

insert into users(username, password) values ('member00', 'pw00');

insert into users(username, password) values ('admin00', 'pw00');

insert into authorities(username, authority) values ('user00', 'ROLE_USER');

insert into authorities(username, authority) values ('member00', 'ROLE_MANAGER');

insert into authorities(username, authority) values ('admin00', 'ROLE_MANAGER');

insert into authorities(username, authority) values ('admin00', 'ROLE_ADMIN');

5. security-context.xml 에 해당 내용을 입력합니다.

1) PasswordEncoder 를 필수적으로 사용해야 하므로 해당 클래스에 관한 bean을 설정합니다.

2) data 를 연결(data-source-ref)하고, password 를 연결(ref) 합니다.

security-context.xml

6. org.zerock.security.CustomNoOpPasswordEncoder.java를 생성합니다.

1) PasswordEncoder 인터페이스를 implements 하였습니다. (Spring Security에서 요구)

2) localhost:8080/security/member 를 주소창에 입력하여,

DB에 입력했던 'member00', 'pw00'이 로그인 되는지 확인합니다.

3) DB에 member00을 'ROLE_MANAGER'로 입력했기 때문에 '/'로 이동하게 될 것입니다.

org.zerock.security.CustomNoOpPasswordEncoder.java

※ 자세한 로그 정보를 보고 싶다면

src/main/resources/log4j.xml 에서 <root>의 <priority value="info"> 로 수정합니다.

[기존의 테이블을 이용하는 경우]

JDBC 테이블을 이용하지 않고 기존의 테이블을 이용하는 경우입니다.

1. 회원관리 기능을 위한 테이블을 생성합니다.

create table tbl_member (

userid varchar(50) not null primary key,

userpw varchar(100) not null,

username varchar(100) not null,

regdate datetime default current_timestamp,

updatedate datetime default current_timestamp on update current_timestamp,

enabled char(1) default '1'

);

2. Spring Security를 위해 권한 정보를 저장하는 테이블을 생성합니다.

create table tbl_member_auth (

userid varchar(50) not null,

auth varchar(50) not null,

constraint fk_member_auth foreign key(userid) references tbl_member(userid)

);

3. security-context.xml 에 BCryptPasswordExcoder Bean을 등록합니다.

security-context.xml

4. 인코딩된 패스워드를 가지는 사용자가 추가되는지 테스트를 해봅니다.

src/test/java/org.zerock.security.MemberTests.java 를 생성하고 테스트합니다.

src/test/java/org.zerock.security.MemberTests.java

테스트 결과, 0부터 99까지 userid 와 username 이 for 문에 맞게, userpw가 암호화되어 insert 되었음을 확인할 수 있습니다.

5. 생성된 사용자에 권한을 추가하는 Test도 진행합니다.

1) 4번에서 실행한 @Test 는 주석처리 후, 권한을 추가하는 Test를 진행합니다. setString2가 i에 따라 부여되는

권한이 다를 뿐 나머지 원리는 동일합니다.

MemberTests.java

결과 확인, user80 미만까지는 ROLE_USER, user80 ~ 89 까지는 ROLE_MEMBER, user 90 ~ 99 까지는 ROLE_ADMIN

[쿼리를 이용하는 인증]

1. security-context.xml 에서 username 과 authroities 권한을 검색하는 sql문을 이용해서도 인증할 수 있습니다.

security-context.xml, tb_member 가 아니라 tbl_member입니다. 오타입니다.

결과확인, 인증이 잘 되었습니다.

[커스텀 UserDetailsSerivice 활용]

사용자가 원하는 방식으로 인가/인증 처리를 하기 위해서는

직접 UserDetailsService 인터페이스를 구현해서 처리합니다.

loadUserByUsername() 이라는 메서드의 반환 타입인 UserDetails 역시 인터페이스로,

사용자의 정보와 권한 정보 등을 담는 타입입니다.

UserDetails 타입은 getAuthorities(), getPassword(), getUserName() 등의

여러 추상 메소드를 가지고 있어서, 개발 전에 이를 직접 구현할 것인지

UserDetatils 인터페이스를 구현해 둔 Spring Security의 여러 하위 클래스를 이용할 것인지 판단해야 합니다.

1. 회원 도메인, 회원 Mapper를 설계합니다.

1) MemberVO 클래스를 생성합니다.

2) AuthVO 클래스를 생성합니다.

3) MemberMapper.java(인터페이스) 를 생성하고 MemberMapper.xml을 정의합니다.

MemberVO.java, AuthVO.java, MemberMapper.java(인터페이스)

tbl_member(왼쪽 테이블)을 기준으로 Join 하는 것입니다.

tbl_member의 모든 Row가 결과값에 반드시 한 줄 이상 나오는 보장을 받게 됩니다.

즉, tbl_member_auth 가 null 일 경우에도 tbl_member 는 나오는 것입니다.

http://rapapa.net/?p=311

Mysql Join 해부(Left, Right, Outer, Inner Join) – Rapapa Dev Story

Mysql Join 해부(Left, Right, Outer, Inner Join) admin 「개발 이야기」 8 Comments Mysql DB를 다룰 때 초보 수준에서 약간 중급으로 넘어가면서 흔히들 많이 어려워 하는 것이 Join 구문입니다. 먼저, 아래와 같은 테이블 두개가 있다고 합시다. 1 2 3 mysql > select * from demo_people; +————+————–+——+ | name | phone | pid | +————+————–+——+ | Mr Brown | 01225 708225 | 1 | | Miss...

rapapa.net

MemberMapper.xml

2. Mapper가 동작하는지 테스트 하기 위해 MemberMapperTests.java 를 생성합니다.

MemberMapperTests.java

MemberMapperTests.java 테스트 결과

3. CustomUserDetailsService.java 를 생성합니다.

Spring Security의 UserDetailsService를 구현하고,

MemberMapper 타입의 인스턴스를 주입받아서 실제 기능을 구현한 Service 클래스입니다.

CustomUserDetailsService.java

4. security-context.xml 에 CustomUserDetailsService 에 관한 bean을 생성하고 ,

authentication-provider를 추가합니다.

security-context.xml

아직은 UserDetails loadUserByUsername()의 return 이 null 이라서 오류가 납니다.

[MemberVO를 UsersDetails 타입으로 변환하기]

1. User 를 상속한 CustomUser.java를 생성합니다.

1) User 도 UserDetails 인터페이스를 구현했으므로 CustomUser도 구현합니다.

CustomUser.java @Getter 어노테이션도 추가해야합니다.

2. CustomUserDetailsService.java 에서 null 로 반환하던 것을

CustomUser가 UserDetail 인터페이스를 구현한 객체로 반환하는 것으로 수정합니다.

CustomUserDetailsService.java

결과 확인

[Spring Security를 JSP 에서 사용하기]

1. admin.jsp 에 principal(접근주체, 보호받는 Resource에 접근하는 대상, CustomerUser 객체)의 속성을

나열합니다. (로그인한 사용자 정보)

https://blog.naver.com/tnwnsrla/222405142142

 

Spring Security

오늘 배웠는데.. 필터의 느낌으로 설정을 하는거 같은데, 정확히 와닿지가 않아서 구글링해보았습니다. 아...

blog.naver.com

admin.jsp

결과확인

[표현식을 이용하는 동적 화면 구성]

1. all.jsp 에 표현식을 이용해서 동적 화면을 구성하겠습니다.

all.jsp isAnonymous(비로그인) 결과

all.jsp isAuthenticated(로그인) 결과

[자동로그인 (remember-me)]

1. Spring Security 의 경우 'remember-me' 기능을 메모리상에서 처리하거나,

DB를 이용하는 형태로 약간의 설정만으로 구현이 가능합니다.

2. security-context.xml 에는 <security:remeber-me> 태그를 이용해서 기능을 구현합니다.

3. <security:remember-me>에는 아래와 같이 여러 속성이 있습니다.

1) key

(1) 쿠키에 사용되는 값을 암호화하기 위한 키(key) 값

2) data-source-ref

(1) DataSource를 지정하고 테이블을 이용해서 기존 로그인 정보를 기록(옵션)

3) remember-me-cookie

(1) 브라우저에 보관되는 쿠키의 이름을 지정합니다. 기본값은 'remember-me'

4) remember-me-parameter

(1) 웹 화면에서 로그인할 때 'remember-me'는 대부분 Checkbox를 이용해서 처리합니다.

(2) 이 때 Checkbox 태그의 name 속성을 의미합니다.

5) token-validity-seconds

(1) 쿠키의 유효시간을 지정합니다.

 

[DB를 이용하는 자동 로그인]

1. 별도의 코드 생성없이 Table 생성만으로도 처리 가능합니다.

1) username = userid, token = cookie 값, last_used = 최종로그인 시간을 의미합니다.

2) Spring Security 가 제공하는 Field 들로 구성되어 있어서, 따로 SQL 문을 작성할 필요 없이

자동적으로 Data를 가져오고 저장합니다.

-- 자동로그인을 위한 테이블

create table persistent_logins (

username varchar(64) not null,

series varchar(64) primary key,

token varchar(64) not null,

last_used timestamp not null

);

2. security-context.xml 에 다음과 같은 설정코드를 작성합니다.

security-context.xml 토큰시간을 7일로 설정

3. customLogin.jsp 에 checkbox 를 넣습니다. name="remember-me" 여야 합니다.

customLogin.jsp

로그인하였을 때, expire가 7일 후가 만료인 Coockie 가 생성되었으면 성공입니다.

DB에도 자동으로 insert 되었음을 확인할 수 있습니다.

로그인 후 브라우저를 종료하고 다시 /security/admin에 접속하면 똑같은 Cookie : remember-me 값이 있음을 확인할 수 있습니다.

[로그아웃 시 쿠키삭제]

1. 자동로그인 기능을 이용하는 경우에 사용자가 로그아웃을 하면 기존과 달리 자동 로그인에 사용하는

쿠키도 삭제해 주도록 쿠키를 삭제하는 항목을 security-context.xml에 지정합니다.

security-context.xml

Logout 시 쿠키가 삭제되고, DB도 삭제됩니다.

[어노테이션을 이용하는 Spring Security 설정]

1. Spring Security 어노테이션을 사용하기 위해 Servlet-context.xml 에 Namespace에 security를

추가하고(사진생략) 해당 문구를 추가합니다.

servlet-context.xml

2. SecurityController.java 에 Spring Security @ 을 사용하는 메소드를 추가합니다.

SecurityController.java

로그인을 하고 주소창에 security/annoMember 를 입력하였을 때, 404 오류가 나면 성공입니다.

(jsp를 만들지 않았기 때문에)

[기존 프로젝트에 Spring Security 접목하기]

기존에 만들었던 게시판 프로젝트에 Spring Security를 접목합니다.

로그인과 회원가입 페이지의 작성

기존화면과 컨트롤러에 Security 관련 내용 추가

Ajax 부분의 변경이 필요합니다.

[로그인 페이지 처리]

1. customLogin.jsp를 bootstrap을 사용할 수 있게 구성합니다. 해당 내용은 파일첨부도 하겠습니다.

첨부파일

customLogin.jsp

 파일 다운로드

customLogin.jsp 1

customLogin.jsp 2

결과화면, 로그인도 되는지 확인해 봅니다.

2. 기존에 로그인 성공여부에 따라 memeber, admin으로 보내던 설정을 막습니다.

security-context.xml

(기존 프로젝트를 복사하고 새로운 프로젝트를 생성해서 하겠습니다.)

[게시물 작성 시 Spring security 처리]

1. BoardControllr.java 에 Get/Post register() 메소드에 @PreAuthorize("isAuthenticated()")를

추가합니다.

BoardController.java

수업 끝..