1. Spring Sercurity 라이브러리 의존 설정 (pom.xml)
<!-- Spring Security 추가-->
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-web</artifactId>
<version>4.2.20.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>4.2.20.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
<version>4.2.20.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<version>4.2.20.RELEASE</version>
<scope>test</scope>
</dependency>
<!-- Spring Security 종료-->
2. 필터 설정 (web.xml)
- 필터 기능을 사용해 서블릿에 도달하기 전 요청을 가로채서 작업할 수 있도록 해줌
- 모든 URL(/*) 요청을 해당 필터에서 먼저 가로채겠다는 의미
<!-- spring security 적용을 위한 filter 설정 -->
<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>
3. 시큐어리티 컨텍스트 설정(security-context.xml)
- 스프링에서 제공해주는 기능들을 이용할 때는 컨테이너(컨텍스트)에 등록
- 컨테이너가 생성되면서 그 안의 설정을 읽어 적절한 Bean 객체를 생성해주고 사용자가 필요할 때 제공
<?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"
xsi:schemaLocation="http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<security:http auto-config="true" use-expressions="true">
<security:csrf disabled="true"/>
<security:form-login
username-parameter="user_id"
password-parameter="user_pw"
login-processing-url="/login/login_check"
login-page="/login/loginPage"
authentication-success-handler-ref="LoginSuccessHandler"
authentication-failure-handler-ref="LoginFailHandler"
always-use-default-target="true" //로그인 성공시 항상 default-target-url 페이지로 이동하는 설정
default-target-url="/info/mainPage"
/>
<security:logout
logout-url="/security_logout"
logout-success-url="/login/loginPage"
invalidate-session="true"
delete-cookies="true"
/>
<security:intercept-url pattern="/resources/**" access="permitAll" />
<security:intercept-url pattern="/login/loginPage" access="isAnonymous()"/>
<security:intercept-url pattern="/**" access="authenticated"/>
<!-- <security:intercept-url pattern="/**" access="hasAnyRole('ROLE_ADMIN, ROLE_USER')"/> -->
<security:access-denied-handler error-page="/login/loginPage"/>
</security:http>
<-- 인증 로직 : 평문 패스워드를 암호화해서 DB의 암호화 된 패스워드와 비교해주는 작업-->
<security:authentication-manager>
<security:authentication-provider ref="userLoginAuthenticationProvider"/>
</security:authentication-manager>
<!-- 패스워드 단방향 암호화 -->
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"/>
</beans>
4. UserLoginAuthenticationProvider (로그인 인증 로직)
- 로그인을 요청한 사용자의 NO, ID, PW, 권한 정보를 DB에서 가져와 스프링 Security에게 전달(LoginService에서 DetailsVo를 가져옴)
- 로그인 성공시 => Success Handler
- 로그인 실패시 => Fail Handler
package com.choongang.bcentral.user.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.*;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.choongang.bcentral.user.vo.UserDetailsVo;
@Service
public class UserLoginAuthenticationProvider implements AuthenticationProvider {
@Autowired
private LoginService loginService; // DB의 값을 가져다주는 커스터마이징 클래스
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder; // 패스워드 암호화 객체
@Override // 인증 로직
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
/* 사용자가 입력한 아이디, 비밀번호 */
String userId = authentication.getName();
String userPw = (String) authentication.getCredentials();
/* DB에서 가져온 정보 */
UserDetailsVo userDetails = (UserDetailsVo) loginService.loadUserByUsername(userId);
/* 인증 진행 */
// DB에 정보가 없는 경우 예외 발생 (아이디/패스워드 잘못됐을 때와 동일한 것이 좋음)
// ID 및 PW 체크해서 안 맞을 경우 (matches를 이용한 암호화 체크를 해야함)
if (userDetails == null || !userId.equals(userDetails.getUsername())
|| !bCryptPasswordEncoder.matches(userPw, userDetails.getPassword())) {
throw new BadCredentialsException(userId);
// 계정 정보 맞으면 나머지 부가 메소드 체크 (이부분도 필요한 부분만 커스터마이징 하면 됨)
// 잠긴 계정일 경우
} else if (!userDetails.isAccountNonLocked()) {
throw new LockedException(userId);
// 비활성화된 계정일 경우
} else if (!userDetails.isEnabled()) {
throw new DisabledException(userId);
// 만료된 계정일 경우
} else if (!userDetails.isAccountNonExpired()) {
throw new AccountExpiredException(userId);
// 비밀번호가 만료된 경우
} else if (!userDetails.isCredentialsNonExpired()) {
throw new CredentialsExpiredException(userId);
}
// 다 썼으면 패스워드 정보는 지워줌 (객체를 계속 사용해야 하므로)
userDetails.setUser_pw(null);
/* 최종 리턴 시킬 새로만든 Authentication 객체 */
Authentication newAuth = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
return newAuth;
}
@Override
// 위의 authenticate 메소드에서 반환한 객체가 유효한 타입이 맞는지 검사
// null 값이거나 잘못된 타입을 반환했을 경우 인증 실패로 간주
public boolean supports(Class<?> authentication) {
// 스프링 Security가 요구하는 UsernamePasswordAuthenticationToken 타입이 맞는지 확인
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}
5. LoginSuccessHandler
package com.choongang.bcentral.user.service;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Service;
import com.choongang.bcentral.mapper.UserSQLMapper;
@Service("LoginSuccessHandler")
public class LoginSuccessHandler implements AuthenticationSuccessHandler{
@Autowired
UserSQLMapper userSQLMapper;
@Override
public void onAuthenticationSuccess(HttpServletRequest request,
HttpServletResponse response,
Authentication auth) throws IOException, ServletException {
HttpSession session = request.getSession();
String user_id = auth.getName();
// 로그인 성공 시 유저 마지막 로그인 시간 업데이트
userSQLMapper.lastLogin(user_id);
// 로그인 성공 시 session에 유저 정보 담기
session.setAttribute("userInfo", userSQLMapper.selectUser(user_id));
response.sendRedirect("/choongang/info/mainPage");
}
}
'수업 내용 > 기업 프로젝트 (D조)' 카테고리의 다른 글
사용자 관리 (0) | 2022.04.11 |
---|---|
(103일차) 3월 24일 (0) | 2022.03.24 |
(96일차) 3월 15일 (0) | 2022.03.15 |
(95일차) 3월 14일 (0) | 2022.03.14 |
(94일차) 3월 11일 (0) | 2022.03.11 |