-
로그인 기능 구현(Spring + MyBatis + Spring Security)취업용 Spring 프로젝트/기능 내역 2019. 7. 17. 13:21
기능 - 데이터베이스의 데이터와 사용자 입력 데이터를 비교해 같으면 main페이지로 이동
- 권한 없는 사용자는 로그인 페이지 외 다른 페이지 접속 불가
spring-security 라이브러리 추가
<dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>4.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.2.3.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.2.3.RELEASE</version> </dependency>
필터 추가 - web.xml
*주의 - security 필터가 먼저 작동되면 encoding 필터가 작동하지 않는다.
<filter> <filter-name>encoding</filter-name> <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class> <init-param> <param-name>encoding</param-name> <param-value>UTF-8</param-value> </init-param> </filter> <filter-mapping> <filter-name>encoding</filter-name> <url-pattern>/*</url-pattern> </filter-mapping> <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>
security 설정 파일 추가 - web.xml
<context-param> <param-name>contextConfigLocation</param-name> <param-value> /WEB-INF/spring/root-context.xml /WEB-INF/spring/security-context.xml </param-value> </context-param>
security-context.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" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.2.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd"> <context:component-scan base-package="com.management.dao"> </context:component-scan> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/loginPage" access="permitAll"/> <security:intercept-url pattern="/resources/**/**" access="permitAll"/> <security:intercept-url pattern="/**" access="hasAnyRole('USER, ADMIN')" /> <security:form-login username-parameter ="id" password-parameter="pw" login-page="/loginPage" default-target-url="/main" /> </security:http> <security:authentication-manager> <security:authentication-provider ref = "userAuthProvider"/> <security:authentication-provider user-service-ref="userService"/> </security:authentication-manager> <bean id = "userService" class = "com.management.service.CustomUserDetailsService"></bean> <bean id = "userAuthProvider" class = "com.management.service.CustomAuthenticationProvider"></bean> </beans>
<security:http> </security:http> 요소에서 웹 관련 설정을 한다.
<security:intercept-url pattern = "" access = "" /> 에서 접근 권한 설정
*주의 - 정적 파일들이 들어있는 resources는 permitAll(모든 사용자 접근 허용) 적용 해줘야 css,js를 읽어올 수 있다.
- 스프링 시큐리티는 권한이 없는 사용자가 페이지 접근 시 로그인 페이지로 redirect 시켜버리는데,
로그인 페이지에 permitAll을 적용하지 않으면 로그인 페이지에서도 권한을 요구하므로
로그인 페이지가 계속 redirect된다... (소중한 3시간을 날려버린 사소한 오류들)
<security:form-login /> 에서 스프링 시큐리티가 주는 default 로그인 페이지를 커스텀 할 수 있다.
-username-parameter : input 아이디 파라미터명 변경 (default = username)
-password-parameter : input 비밀번호 파라미터명 변경 (default = password)
-login-page : 기본 스프링 시큐리티 페이지를 직접 만든 페이지로 변경
-default-target-url : 로그인 성공 후 이동할 페이지
<security:authentication-manager> </security:authentication-manager> 에서 인증 관련 설정
- 3가지 인터페이스를 이용해 스프링 시큐리티 인증을 구현한다.
org.springframework.security.core.userdetails.UserDetails
- 사용자 정보를 담음 (DTO 역할)
org.springframework.security.core.userdetails.UserDetailsService
- 데이터베이스에서 사용자 데이터를 가져옴
org.springframework.security.core.authentication.AuthenticationProvider
- UserDetailsService에서 가져온 데이터와 사용자 입력 데이터를 비교해 로그인 인증 처리 실행
UserDetails
@SuppressWarnings("serial") public class CustomUserDetails implements UserDetails{ private String id; private String pw; private String authority; private boolean enabled; @Override public Collection<? extends GrantedAuthority> getAuthorities() { ArrayList<GrantedAuthority> auth = new ArrayList<GrantedAuthority>(); auth.add(new SimpleGrantedAuthority(authority)); return auth; } @Override public String getPassword() { return pw; } @Override public String getUsername() { return id; } @Override public boolean isAccountNonExpired() { return true; } @Override public boolean isAccountNonLocked() { return true; } @Override public boolean isCredentialsNonExpired() { return true; } @Override public boolean isEnabled() { return enabled; } }
UserDetails 인터페이스를 구현한 CustomUserDetails 클래스
return 타입 메소드명 설명 String getUsername() 계정의 이름을 리턴 String getPassword() 계정의 패스워드를 리턴 boolean isAccountNonExpired() 계정이 만료되지 않았는지를 리턴 (true = 만료되지 않음) boolean isAccountNonLocked() 계정이 잠겨있지 않았는지를 리턴 (true = 잠겨있지 않음) boolean isCredentialsNonExpired() 계정의 패스워드가 만료되지 않았는지를 리턴 (true = 패스워드가 만료되지 않음) boolean isEnabled() 계정이 사용가능한 계정인지를 리턴 (true = 사용가능한 계정) Collection<? extends GrantedAuthority>
getAuthorities() 계정이 갖고 있는 권한 목록을 리턴 UserDetails 인터페이스의 메소드
AuthenticationProvider
public class CustomAuthenticationProvider implements AuthenticationProvider { @Inject private UserDetailsService service; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { //사용자 입력 값 String id = (String)authentication.getPrincipal(); String pw = (String)authentication.getCredentials(); CustomUserDetails user = (CustomUserDetails)service.loadUserByUsername(id); if(!matchPassword(pw, user.getPassword())) { throw new BadCredentialsException(id); } return new UsernamePasswordAuthenticationToken(id, pw, user.getAuthorities()); } @Override public boolean supports(Class<?> authentication) { return true; } private boolean matchPassword(String pw, String password) { return pw.equals(password); } }
AuthenticationProvider 인터페이스를 구현한 CustomAuthenticationProvider
UserDetailsService
public class CustomUserDetailsService implements UserDetailsService{ @Inject private MemberDAO dao; @Override public UserDetails loadUserByUsername(String id) throws UsernameNotFoundException { CustomUserDetails user = dao.login(id); if(user == null) { throw new UsernameNotFoundException(id); } return user; } }
UserDetailsService 인터페이스를 구현한 CustomUserDetailsService
DAO
@Override public CustomUserDetails login(String id) { return sqlSession.selectOne(namespace + ".login", id); }
Mapper
<select id="login" resultType="CustomUserDetails"> SELECT * FROM member WHERE id = #{id} </select>
동작
로그인 성공
로그인 실패
권한 없는 사용자 접근 시 로그인 redirect
-끝-
'취업용 Spring 프로젝트 > 기능 내역' 카테고리의 다른 글
스케줄러 (Spring + MyBatis) - fullcalendar로 달력 출력 (0) 2019.07.23 MySQL 5.7 → MariaDB 10.3 마이그레이션(Ubuntu 18.04) (0) 2019.07.18 회원가입 (Spring + MyBatis) - 가입하기 구현 (0) 2019.07.15 회원가입 (Spring + MyBatis) - 아이디 중복 및 비밀번호 검사 추가 (0) 2019.07.14 회원가입 (Spring + MyBatis) - 회원 데이터베이스 설계 및 폼 구현 (0) 2019.07.13