이전 코드에서 user, manager, admin url요청이 들어오면 권한이 있는 사람만 접근하도록 했고, 접근이 없는 사람이 들어오려하면 로그인 페이지가 나오는 것을 확인했다. 그 외 다른 페이지들은 모두 접근을 허용해 두었었다.
user, manager, admin으로 접근 요청이 들어오면 인증을 위한 로그인 폼으로 이동하게 수정해보자.
package com.cos.security1.controller;
@GetMapping("/login")
public String login(){
return "loginForm";
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>login page</title>
</head>
<body>
<h1>로그인 페이지</h1>
<hr/>
<form>
<input type="text" name="username" placeholder="Username"/> <br/>
<input type="password" name="password" placeholder="Password"/> <br/>
<button>로그인</button>
</form>
</body>
</html>
이제 서버를 실행해 user, manager, admin 페이지를 요청하면 로그인 페이지로 이동하는 것을 볼 수 있다.
이제 회원가입을 구현해보자
package com.cos.security01.model;
import java.sql.Timestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.hibernate.annotations.CreationTimestamp;
import lombok.Data;
// ORM - Object Relation Mapping
@Data
@Entity
public class User {
@Id // primary key
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String username;
private String password;
private String email;
private String role; //ROLE_USER, ROLE_ADMIN
@CreationTimestamp
private Timestamp createDate;
}
User 테이블을 생성했다.
package com.cos.security01.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class IndexController {
@GetMapping({"","/"})
public String index(){
return "index";
}
@GetMapping("/user")
public @ResponseBody String user(){
return "user";
}
@GetMapping("/admin")
public @ResponseBody String admin(){
return "admin";
}
@GetMapping("/manager")
public @ResponseBody String manager(){
return "manager";
}
//스프링 시큐리티가 로그인 url을 낚아챈다.
@GetMapping("/loginForm")
public String loginForm(){
return "loginForm";
}
@GetMapping("/joinForm")
public String joinForm(){
return "joinForm"; //회원가입 페이지
}
@PostMapping("/join")
public String join(){
return "join"; //실제회원가입
}
}
indexController 수정
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf().disable();
http.authorizeRequests()
.antMatchers("/user/**").authenticated()
.antMatchers("/manager/**").access("hasAnyRole('ROLE_MANAGER','ROLE_ADMIN')")
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll()
.and()
.formLogin()
.loginPage("/loginForm");
return http.build();
}
아래서 4번째 줄 loginForm으로 수정
<form>
...
</form>
<!--회원가입 링크 추가-->
<a href="/joinForm">회원가입을 아직 하지 않으셨나요?</a>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>회원가입 페이지</title>
</head>
<body>
<h1>회원가입 페이지</h1>
<hr/>
<form action="/join" method="POST">
<input type="text" name="username" placeholder="Username"/> <br/>
<input type="password" name="password" placeholder="Password"/> <br/>
<input type="email" name="email" placeholder="Email"/> <br/>
<button>회원가입</button>
</form>
</body>
</html>
package com.cos.security01.repository;
import com.cos.security01.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
public interface UserRepository extends JpaRepository <User, Integer> {
}
repository 패키지를 만들고 그 안에 UserRepository를 만들었다.
근데 왜 @Repository 어노테이션을 사용안하고 JpaRepository를 상속받았을까?
그 이유는 JpaRepository는 기본 CRUD 메소드를 가지고 있는 메소드여서 내가 이를 따로 안 만들고 재활용할 수 있다.
그리고 JpaRepository를 상속받으면 IoC 컨테이너에 자동 등록된다.
@Autowired
private UserRepository userRepository;
@PostMapping ("/join")
public String join(User user){
System.out.println(user);
user.setRole("ROLE_USER");
userRepository.save(user);
return "join"; //실제회원가입
}
일단 임의로 user의 role 컬럼에 "ROLE_USER"라고 값을 입력했다.
이렇게 하고 실행하면 유저 가입이 제대로 실행되는 것을 확인할 수 있는데!!!
Spring Security로 로그인을 할 수가 없다.
@Bean
public BCryptPasswordEncoder encodePwd(){
return new BCryptPasswordEncoder();
} //해당메소드의 리턴되는 오브젝트를 ioc로 등록해준다
encodePwd() 메소드 추가
@Bean을 하면 해당 메소드에서 리턴되는 오브젝트를 IoC로 등록해준다.
@Autowired
private BCryptPasswordEncoder bCryptPasswordEncoder;
@PostMapping ("/join")
public String join(User user){
//처음에 사용자가 입력한 값 출력
System.out.println(user);
user.setRole("ROLE_USER");
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.setPassword(encPassword);
userRepository.save(user);
//암호화 적용 후 값 출력
System.out.println(user);
return "redirect:/loginForm"; //redirect를 하면 loginForm함수를 호출해준다
}
이렇게 들어온 password를 시큐리티를 적용하여 암호화하여 등록하는 코드를 작성했다.
전
User(id=0, username=123, password=123, email=123@123.com, role=null, createDate=null)
후
User(id=2, username=123, password=$2a$10$hTR3auQslSFvPHSb0XfBFeS2iIHMpv5XYMDpJGUce6c3XHflYbqsa, email=123@123.com, role=ROLE_USER, createDate=2023-03-09 15:41:06.006)
이렇게 내가 123이라고 입력했던 비밀번호에 스프링 시큐리티가 적용되어 DB에 입력되는 것을 볼 수 있다.
끝!@@@@!!!