스프링 시큐리티
1. pom.xml 에 라이브러리 추가 (동일한 버전)
서블릿의 여러 종류의 필터와 인터셉터를 이용해서 처리됨
spring-security-web
spring-security-core
spring-security-taglibs
spring-security-config
2. 설정 파일 생성
security-context.xml (WEB-INF/spring 폴더 안에 생성)
네임스페이스 - security 항목 체크
web.xml 필터 추가
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<context-param>
<param-value>
/WEB-INF/spring/root-context.xml
/WEB-INF/spring/security-context.xml
</param-value>
</context-param>
3. security-context.xml 설정
3-1) 시작점 <security:http>
(메소드 종류)
perminAll : 모두에게 허용
hasRole('권한') : 권한이 있는지 체크
3-2) 인증 <security:authentication-manager>
3-3). 접근제한 설정 <security:intercept-url pattrtn="sample/all" access="permitAll">
<security:http>
<security:intercept-url pattrtn="페이지 경로" access="">
<security:intercept-url pattrtn="sample/all" access="permitAll">
<security:intercept-url pattrtn="sample/mamber" access="hasRole('ROLE_MEMBER')">
<security:intercept-url pattrtn="sample/admin" access="hasRole('ROLE_ADMIN')">
</security:http>
3-4) 로그인 페이지 설정 <security:form-login/>
3-5) 인증(Authentication)과 권한(Authorization) 부여
Authentication-manager : 인증 매니저 (책임자)
ProviderManager : 인증 제공자 (인증 처리 담당)
-> Authentication-Provider 타입의 객체를 이용해서 처리함
UserDetailsService : 실제 사용자의 정보와 사용자가 가진 권한의
정보를 처리해서 반환
<security:authentication-manager>
<security:authentication-provider>
<security:user-service>
<security:user name="member" password="member" authorities="ROLE_MEMBER" />
<security:user name="admin" password="admin" authorities="ROLE_MEMBER, ROLE_ADMIN" />
</security:user-service>
</security:authentication-provider>
</security:authentication-manager>
4. 접근거부 페이지 설정
4-1) error-page 지정하기
- security-context.xml에 설정
<security:access-denied-handler error-page="/accessError" />
- CommonController에서 /accessError 처리하도록 작성
@GetMapping("/accessError") ---> accessError.jsp로 이동
public void accessDenied(Authentication auth, Model model) {
model.addAttribute("msg", "접근 거부");
}
4-2) AccessDeniedHandler 인터페이스 구현하기
CustomAccessDeniedHandler 클래스 생성
(AccessDeniedHandler 인터페이스 구현 클래스)
security-context.xml 빈으로 등록
<security:access-denied-handler>태그의
error-page 속성 대신에 ref 속성으로 변경
ref 속성 값으로 bean id를 지정
5. 커스텀 로그인 페이지 설정
5-1) 로그인 페이지 지정
<security:form-login login-page="/customLogin" />
5-2) CommonControllrt에 로그인 요청 처리 추가
@GetMapping("/customLogin") ---> customLogin.jsp로 이동
public void loginInput(String error, String logout, Model model) {
if(error != null) {
model.addAttribute("error", "로그인 오류 발생");
}
if(logout != null) {
model.addAttribute("logout", "로그아웃");
}
}
5-3) customLogin.jsp 생성
<form method="post" action="/login">
<input type="text" name="username" />
<input type="password" name="password" />
<input type="submit" />
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
</form>
5-4) 로그인 성공 처리 후 특정한 동작을 하도록 제어
AuthenticationSuccessHandler 인터페이스 생성
- customLoginSuccessHandler 클래스 생성
(AuthenticationSuccessHandler 인터페이스 구현 클래스)
- security-content.xml에 빈으로 등록
- authentication-success-handler-ref="customLoginSuccess" 속성 지정
5-5) 로그아웃 처리
- security-content.xml logout 설정
<security:logout logout-url="/customLogout" invalidate-session="true">
- CommonController /customLogout 처리 작성
@GetMapping("/customLogout") ---> customLogout.jsp로 이동
public void logoutGet() {
}
- customLogout.jsp 생성
<form action="/customLogout" method="post">
<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}" />
<button>로그아웃</button>
</form>
6. JDBC를 이용한 인증/권한 처리
Authentication Manager : 인증과 권한 처리
6-1) 인증이나 정보를 제공하는 존재 (Provider)
6-2) UserDetailsService 인터페이스 구현 존재 활용
jdbc를 이용하기 위한 설정
<security:user-service>
<security:user name="member" password="member" authorities="ROLE_MEMBER" />
<security:user name="admin" password="admin" authorities="ROLE_MEMBER, ROLE_ADMIN" />
</security:user-service>
<security:authentication-manager>
<security:authentication-provider>
<security:jdbc-user-service data-source-ref="dataSource" />
</security:authentication-provider>
</security:authentication-manager>
- default 테이블 생성 방식
create table users (
username varchar2(50) not null primary key,
password varchar2(50) not null,
enabled char(1) default '1'
);
create table authorities (
username varchar2(50) not null,
authority varchar2(50) not null,
constraint fk_authorities_users foreign key(username) references users(username)
);
- 인증/권한을 위한 테이블 설계 (수업에서 사용한 테이블 생성 방식)
create table tbl_member(
userid varchar2(50) not null primary key,
userpw varchar2(100) not null,
username varchar2(100) not null,
regidate date default sysdate,
updatedate date default sysdate
)
create table tbl_member_auth(
userid varchar2(50) not null,
auth varchar2(50) not null,
constraint fk_member_auth foreign key(userid)
references tbl_member(userid)
)
BCryptPasswordEncoder 클래스를 이용한 패스워드 보호
BCryptPasswordEncoder 클래스는 이미 시큐리티 API에 포함되어 있으므로
구현하지 않음 -> bean으로 등록만 해줌!!!
<bean id="bcriptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<security:authentication-manager>
<security:authentication-provider>
<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 = ?"
/>
// users, authorities 추가하는 이유 : default 형식이 아니라
// 다른 이름, 방식으로 테이블 설계해서 이 쿼리들을 추가해줌
<security:password-encoder ref="bcriptPasswordEncoder">
</security:authentication-provider>
</security:authentication-manager>
7. UserDetailsService 인터페이스 구현 방식
7-1) 회원 클래스, 회원 권한 클래스 생성
org.green.domain 패키지 생성
MemberVO 클래스
AuthVO 클래스
7-2) MemberMapper 인터페이스 생성, MemberMapper.xml 생성
<resultMap type="org.green.domain.MemberVO" id="memberMap">
</resuleMap>
<resultMap type="org.green.domain.AuthVO" id="authMap">
</resuleMap>
resultMap="memberMap"
<select id="read" resultMap="memberMap">
select mem.userid, userpw, username, enabled, regidate, updatedate, auth
from tbl_member mem left outer join tbl_member_auth auth
on mem.userid = auth.userid
where mem.userid = #{userid}
</select>
7-3) CustomerUserDetailsService 클래스 생성
(UserDetailsService 인터페이스 구현)
UserDetailsService 인터페이스의 추상메소드 - loadUserByUsername()
UserDetails 타입 -> 인터페이스
UserDetails 상속받은 User클래스 (자동으로 생성되있음)
(org.springframework.security.core.userdetails.User클래스
-> UserDetails를 구현하고있음)
User 상속받은 CustomUser클래스 생성
org.green.security.domain패키지 CustomUser클래스
security-context.xml
- 클래스를 빈으로 등록
<bean id="customUserDetailsService" class="org.green.security.CustomUserDetailsService"></bean>
- 인증 제공자 수정 (authentication-provider)
user-service-ref 속성으로 지정
<security:authentication-provider user-service-ref="customUserDetailsService">
8. 스프링 시큐리티 jsp에서 사용하기
사용자 정보 나타내기
8-1) 시큐리티 관련 태그 라이브러리 사용 선언
<%@ taglib uri="http://www.springframework.org/security/tags" prefix="sec" %>
8-2) 인증된 데이터 정보 <sec:authentication property="principal" />
<sec:authentication property="principal.member.userName">
-> UserDetailsService에서 반환된 객체
8-3) 인가 정보 <sec:authorize />
-> 로그인된 상태라면 로그아웃을 나타내고, 로그인되지 않은
상태라면 로그인을 나타내기
isAnonymous() 익명의 사용자일 경우 true
(로그인을 하지않은 경우도 포함)
isAuthenticated() 인증된 사용자라면 true
(로그인된 경우도 포함)
<sec:authorize access="isAnonymous()">
<a href="/customLogin">로그인</a>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<a href="/customLogin">로그아웃</a>
</sec:authorize>