<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- JSP 사용 -->
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-jasper</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>5.1.3</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jquery</artifactId>
<version>3.6.0</version>
</dependency>
# tomcat의 기본 port 변경
server.port=8090
server.servlet.context-path=/app
# JSP 설정
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp
public class Member {
@NotBlank(message = "적어도 한 글자 이상")
String userid;
String passwd;
@NotBlank(message = "적어도 한 글자 이상")
String username;
: security 의존성 설정, 계정과 비밀번호 설정
: 회원가입 & 비밀번호 암호화
-- use testdb;
-- show full columns from todo;
drop table if exists member;
create table member
( userid varchar(255) not null COMMENT '아이디',
passwd varchar(255) not null COMMENT '비밀번호',
username varchar(255) not null COMMENT 'TODO 작성자',
primary key(userid)
);
<!-- https://mvnrepository.com/artifact/org.mybatis.spring.boot/mybatis-spring-boot-starter -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
# DB 연동 위한 4가지 정보 설정
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/testdb
spring.datasource.username=root
spring.datasource.password=1234
# 별칭
mybatis.type-aliases-package=com.exam.dto
# mapper 등록 (하나로 퉁치기)
mybatis.mapper-locations=com/exam/mapper/*Mapper.xml
// 비밀번호 암호화 (필수 !!!!!!!!!!)
String encptPw = new BCryptPasswordEncoder().encode(member.getPasswd());
member.setPasswd(encptPw);
: 기본적으로 동작되는 security의 FilterChain을 커스터마이징이 가능하다
: 이전에는 인증이 필요없는 요청도 (/home, /signup) 인증하도록 강제함
예> 불필요한 인증 제거
로그인 화면을 사용자가 만든 화면으로 변경
인증 실패시 / 인증 성공시 사용자가 특정 위치로 리다이렉트 가능
로그아웃 커스터마이징
: 커스터마이징 시작했으면 인증 제거 ~ 로그아웃 끝까지 재설정 작업이 필요함
@Configuration
public class SecurityFilterChainConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception{
// 커스터마이징 처리
// 1. 불필요한 인증 제거
http.authorizeRequests()
.antMatchers("/login","/home","/signup","/webjars/**","/images/**").permitAll()
.anyRequest()
.authenticated();
// 2. 로그인 관련 작업
http.formLogin() // 사용자가 만든 로그인화면으로 인증처리 하겠음
.loginPage("/login") // 로그인 페이지로 갈수 있는 요청맵핑값 <a href="login">로그인
.loginProcessingUrl("/auth") // <form action="auth" method="post"
.usernameParameter("userid") // <input name="userid">
.passwordParameter("passwd") // <input name="passwd">
.failureForwardUrl("/login_fail") // 로그인 실패시 리다이렉트되는 요청맵핑값
.defaultSuccessUrl("/login_success", true); // 로그인 성공시 리다이렉트되는 요청맵핑값
// 3. csrf 비활성화
http.csrf().disable();
//4. 로그아웃 관련 작업
http.logout()
.logoutUrl("/logout") // security가 자동으로 로그아웃 처리해주는 요청맵핑값
.logoutSuccessUrl("/home"); // logout 성공시 리다이렉트 되는 요청맵핑값
return http.build();
}
}
@Component
public class AuthProvider implements AuthenticationProvider {
@Autowired
MemberService memberService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String userid = (String)authentication.getPrincipal(); // name="userid" 값
String passwd = (String)authentication.getCredentials(); // name="passwd" 값
Member mem = memberService.findById(userid);
// String encrptPw = mem.getPasswd(); // NullPointerExcepion 발생되기 때문에 사용안됨.
//Authentication 하위클래스
//로그인 성공시
UsernamePasswordAuthenticationToken token=null;
if(mem!=null && new BCryptPasswordEncoder().matches(passwd, mem.getPasswd())) {
List<GrantedAuthority> list = new ArrayList<>();
//ROLE 설정시 사용됨
list.add(new SimpleGrantedAuthority("USER")); // ADMIN
//암호화된 비번대신에 raw 비번으로 설정
mem.setPasswd(passwd);
token = new UsernamePasswordAuthenticationToken(mem, null, list);
// token = new UsernamePasswordAuthenticationToken(mem, null);
// new UsernamePasswordAuthenticationToken(Principal, Credentials);
// new UsernamePasswordAuthenticationToken(Principal, Credentials, List<GrantedAuthority>);
return token;
}
//로그인 실패시
throw new BadCredentialsException("비밀번호가 일치하지 않습니다. 다시 확인하세요.");
}
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-taglibs</artifactId>
</dependency>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<ul class="navbar-nav">
<!-- 인증이 안된 사용자 -->
<sec:authorize access="isAnonymous()">
<li class="nav-item">
<a class="nav-link" href="login">login</a>
</li>
</sec:authorize>
<sec:authorize access="isAnonymous()">
<li class="nav-item">
<a class="nav-link" href="signup">signup</a>
</li>
</sec:authorize>
<!-- 인증이 된 사용자 -->
<sec:authorize access="isAuthenticated()">
<li class="nav-item">
<a class="nav-link" href="logout">logout</a>
</li>
</sec:authorize>
<sec:authorize access="isAuthenticated()">
<li class="nav-item">
<a class="nav-link" href="mypage">mypage</a>
</li>
</sec:authorize>
</ul>
=> SecurityContextHolder.getContext().getAuthentication() 사용
@GetMapping(value={"/mypage"})
public String mypage() {
// AuthProvider에 저장된 Authentication 얻자
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
Member xxx = (Member)auth.getPrincipal();
return "redirect:home";
}