로그인폼과 회원가입폼 HTML
더보기
로그인폼과 회원가입폼
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>로그인 페이지</title>
</head>
<body>
<h1>로그인 페이지</h1>
<hr>
<form action="/login" method="POST">
<input type="text" name="username" placeholder="UserName"/><br/>
<input type="password" name="password" placeholder="Password"/><br/>
<button>로그인</button>
</form>
<a href = "/joinForm">회원가입을 아직 않으셨나요?</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>회원가입 페이지</title>
</head>
<body>
<h1>회원가입 페이지</h1>
<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>
[ 회원가입 Contoller ]
@PostMapping("/join")
public String join(User user){
System.out.println(user);
// 2. 패스워드 암호화를 추가해줌 securityConfig에도 BcryptpasswordEncoder를 @Bean으로 등록
String rawPassword = user.getPassword();
String encPassword = bCryptPasswordEncoder.encode(rawPassword);
user.setPassword(encPassword);
// 1. userRepository.save(user); // 회원가입 잘됨. 비밀번호 : 1234 => 시큐리티로 로그인을 할수 없음,
// :: 패스워드가 암호화가 안되었기 때문
user.setRole("ROLE_USER");
userRepository.save(user);
return "redirect:/loginForm";
}
[ USER MODEL ]
package com.cos.security1.model;
import lombok.Data;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.sql.Timestamp;
@Entity
@Data
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 REPORSITORY - JPA ]
package com.cos.security1.repository;
import com.cos.security1.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
// CRUD 함수를 JPArepository가 들고 있음
// @Repository라는 어노테이션이 없어도 Ioc가 됨 (자동 빈등록)
// -> JpaRepository를 상속했기 때문
public interface UserRepository extends JpaRepository<User, Integer> {
// findBy규칙 -> username 문법
// seelct * from user where username = #{username}
public User findByUsername(String username);
}
[ config 수정 ]
밑 두줄 추가.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // /login으로 갈때 스프링 시큐리티가 낚아채지 않도록
http.authorizeRequests()
.antMatchers("/user/**").authenticated()
.antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
.antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
.anyRequest().permitAll()// 다른주소는 OK
.and()
.formLogin()
.loginPage("/loginForm") // 로그인안햇을때 403페이지가 뜨는게 아니라 login페이지를 뜨게만들어줌
.loginProcessingUrl("/login") //login 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행
.defaultSuccessUrl("/"); // 로그인이 완료되면 이동할 주소
}
[ userDetails를 상속하는 클래스 생성 ]
유저정보를 저장.
package com.cos.security1.config.auth;
// 시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킴
// 로그인 진행이 완료되면 seisson을 만들어줌 (Security ContextHolder)
// 세션에 들어갈 수 있는 정보(오브젝트) > authentication 타입의 객체
// authentication 안에 User정보가 있어야 함.
// user 오브젝트 타입 > UserDetails 타입 객체
// Security Session => Authentication => UserDetails(PrincipalDetails)
import com.cos.security1.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.ArrayList;
import java.util.Collection;
public class PrincipalDetails implements UserDetails {
private User user; // 콤포지션
public PrincipalDetails(User user){
this.user = user;
}
// 해당 user의 권한을 리턴하는 곳
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> collect = new ArrayList<>();
collect.add(new GrantedAuthority() {
@Override
public String getAuthority() {
return user.getRole();
}
});
return collect;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUsername();
}
// 계정 만료
@Override
public boolean isAccountNonExpired() {
return true;
}
// 계정 잠김
@Override
public boolean isAccountNonLocked() {
return true;
}
// 계정 유효기간
@Override
public boolean isCredentialsNonExpired() {
return true;
}
// 계정 정지
@Override
public boolean isEnabled() {
// ex) 휴면계정
// 현재시간 - 로그인시간 => 1년초과하면 return false
return true;
}
}
[ userDetailsService를 상속한 클래스 만들기 ]
이름 그대로 유저의 정보를 저장해주는 서비스
// 시큐리티 설정에서 loginProcessingUrl("/login")
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 ioc되어있는 loadUserByUsername가 함수 실행
package com.cos.security1.config.auth;
import com.cos.security1.model.User;
import com.cos.security1.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
// 시큐리티 설정에서 loginProcessingUrl("/login")
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 ioc되어있는 loadUserByUsername가 함수 실행
@Service
public class PrincaipalDetailsService implements UserDetailsService{
@Autowired
private UserRepository userRepository;
// 시큐리티 session > authentication > userDetails(principalDetails)
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
// html에 꼭 "username"으로 해야함 (String username)과 매칭이 안됨
// 바꾸고 싶다면 security config에 .usernameParameter("username2")
// 그냥 username을 쓰자 ^^
User userEntity = userRepository.findByUsername(username);
if(userEntity != null){
return new PrincipalDetails(userEntity);
}
return null;
}
}
[ userRepository 에는 유저의 정보를 조회하는 부분 추가 ]
// findBy규칙 -> username 문법
// seelct * from user where username = #{username}
public User findByUsername(String username);