Before Start.
spring jpa에 대한 세팅이 끝난 다는 가정하에 진행되는 예제 입니다.
jpa 세팅이 안되신 분은 https://writemylife.tistory.com/87?category=833540 참고 해주세요
Step1. 회원 클래스 만들기
user라는 이름으로 제공되는 클래스가 있기 때문에 보통, Account or Member로 회원 클래스를 만듭니다. 저는 Account로 진행 해보겠습니다.
src/main/java/패키지명/Account 폴더를 만들고 그 아래 Account.java를 만듭니다.
Account.java
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.CreationTimestamp;
import javax.persistence.*;
import java.util.Date;
import java.util.List;
@Entity
@Table(name="Account")
@NoArgsConstructor
@EqualsAndHashCode(of = "id")
@Data
public class Account {
@Id
private String id;
@Column(nullable=false)
private String email;
@Column(nullable=false)
private String password;
@CreationTimestamp
private Date regdate;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="uid")
private List<AccountRole> roles;
}
Step2. 컨트롤러 만들기
src/main/java/패키지명/Account 아래 AccountController.java를 만듭니다.
AccountController.java
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import javax.servlet.http.HttpServletRequest;
@Controller
public class AccountController {
@Autowired
AccountService accontService;
@RequestMapping(value="/create", method = RequestMethod.POST)
public String create(Account account, HttpServletRequest httpServletRequest) throws Exception{
accontService.saveAccount(account, httpServletRequest);
return "redirect:/login";
}
@RequestMapping(value="/member/signUp", method = RequestMethod.GET)
public String signUp(){
return "/member/signUp";
}
}
Step3. 레포지터리 만들기
src/main/java/패키지명/Account 아래 AccountRepository.interface를 만듭니다.
AccountRepository.interface
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.Param;
public interface AccountRepository extends CrudRepository<Account, Integer> {
@Query("SELECT account FROM Account account WHERE account.id = :id")
Account findById(@Param("id") String id);
}
Step4. 권한 등급 클래스 만들기
src/main/java/패키지명/Account 아래 AccountRole.java를 만듭니다.
AccountRole.java
import lombok.Data;
import lombok.EqualsAndHashCode;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Data
@Entity
@EqualsAndHashCode(of = "rno")
public class AccountRole {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long rno;
private String roleName;
}
Step5. 서비스 클래스 만들기
src/main/java/패키지명/Account 아래 AccountService.java를 만듭니다.
AccountService.java
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.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.Arrays;
@Service
public class AccountService implements UserDetailsService{
@Autowired
private AccountRepository AccountRepository;
public void saveAccount(Account account, HttpServletRequest httpServletRequest) throws Exception {
AccountRole role = new AccountRole();
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
role.setRoleName("USER");
account.setRoles(Arrays.asList(role));
account.setPassword(passwordEncoder.encode(account.getPassword()));
AccountRepository.save(account);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
Account account = AccountRepository.findById(username);
if(account == null)
throw new UsernameNotFoundException(username);
SecurityAccount securityAccount = new SecurityAccount(account);
return securityAccount;
}
}
Step6. 보안 클래스 만들기
src/main/java/패키지명/Account 아래 SecurityAccount.java를 만듭니다.
SecurityAccount.java
import lombok.Getter;
import lombok.Setter;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import java.util.ArrayList;
import java.util.List;
@Getter
@Setter
public class SecurityAccount extends User {
private static final String ROLE_PREFIX = "ROLE_";
private static final long serialVersionUID = 1L;
public SecurityAccount(Account account){
super(account.getId(), account.getPassword(), makeGrantedAuthority(account.getRoles()));
}
private static List<GrantedAuthority> makeGrantedAuthority(List<AccountRole> roles){
List<GrantedAuthority> list = new ArrayList<>();
roles.forEach(role -> list.add(new SimpleGrantedAuthority(ROLE_PREFIX + role.getRoleName())));
return list;
}
}
Step7. 로그인 화면 만들기
공통 css 파일
src/main/resources/static 아래 login.css를 만듭니다.
login.css
.login-page {
width: 100%;
padding: 8% 0 0;
margin: auto;
}
a{
text-decoration-line: none;
}
.form {
position: relative;
z-index: 1;
background: #FFFFFF;
max-width: 360px;
margin: 0 auto 100px;
padding: 45px;
text-align: center;
box-shadow: 0 0 20px 0 rgba(0, 0, 0, 0.2), 0 5px 5px 0 rgba(0, 0, 0, 0.24);
}
.form .label{
width : 30%;
}
.form .content{
width : 50%
}
.form input {
font-family: "Roboto", sans-serif;
outline: 0;
background: #f2f2f2;
width: 100%;
border: 0;
margin: 0 0 15px;
padding: 15px;
box-sizing: border-box;
font-size: 14px;
}
.form .submit {
display : block;
font-family: "Roboto", sans-serif;
text-transform: uppercase;
outline: 0;
background: #4CAF50;
width: 100%;
padding: 15px 0px 15px 0px;
color: #FFFFFF;
font-size: 14px;
cursor: pointer;
margin-top:5px;
font-weight: bold;
}
.form .submit:hover,.form .submit:active,.form .submit:focus {
background: #43A047;
}
.form .message {
margin: 15px 0 0;
color: #b3b3b3;
font-size: 12px;
}
.form .message a {
color: #4CAF50;
text-decoration: none;
}
.form .register-form {
display: none;
}
.check_id{
width:17px !important;
height:17px !important;
margin: 0px 5px 0px !important;
}
.btn{
font-family: "Roboto", sans-serif;
text-transform: uppercase;
outline: 0;
background: #7D7F82;
width: 100%;
border: 0;
padding: 15px;
color: #FFFFFF;
font-size: 14px;
cursor: pointer;
margin-top:5px;
font-weight: bold;
}
body {
background: #76b852; /* fallback for old browsers */
background: -webkit-linear-gradient(right, #76b852, #8DC26F);
background: -moz-linear-gradient(right, #76b852, #8DC26F);
background: -o-linear-gradient(right, #76b852, #8DC26F);
background: linear-gradient(to left, #76b852, #8DC26F);
font-family: "Roboto", sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
src/main/resources/templates 아래 login.html를 만듭니다.
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<link rel="stylesheet" th:href="@{/css/login.css}"/>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<div class="login-page">
<div class="form">
<form class="login-form" th:action="@{/login}" method="post">
<input type="text" name="username" placeholder="ID"/>
<input type="password" name="password" placeholder="Password"/>
<input class="submit" type="submit" value="로그인">
<a class="submit" th:href="@{/member/signUp}">회원가입</a>
</form>
</div>
</div>
</body>
</html>
Step8. 회원가입 화면 만들기
src/main/resources/templates/member 아래 signUp.html를 만듭니다.
signUp.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="https://www.thymeleaf.org">
<head>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
<link rel="stylesheet" th:href="@{/css/login.css}"/>
</head>
<body>
<div class="login-page">
<div class="form">
<form class="login-form" th:action="@{/create}" method="post">
<table>
<tr>
<td class="label">아이디</td>
<td class="content"><input type="text" id="id" name="id" placeholder="ID"/></td>
</tr>
<tr>
<td class="label">이메일</td>
<td class="content"><input type="text" id="email" name="email" placeholder="email"/></td>
</tr>
<tr>
<td class="label">비밀번호</td>
<td class="content"><input type="password" id="password" name="password" placeholder="Password"/></td>
</tr>
</table>
<input type="submit" class="submit" value="회원가입">
</form>
</div>
</div>
</body>
</html>
Step9. WebSecurityConfig 수정
WebSecurityConfig.java의 configure메소드를 수정합니다.
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/hello").authenticated()
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.permitAll()
.and()
.logout()
.permitAll();
}
Step10. 결과 확인
첫 화면
hello 이동 누른후 자동으로 로그인 화면으로 이동
회원가입 화면
테이블 확인
로그인 적용은 다음 글에서 진행하겠습니다~~
출처 및 참고 사이트
https://github.com/kdevkr/spring-demo-security
https://xmfpes.github.io/spring/spring-security/
'웹프로그래밍 > spring~~' 카테고리의 다른 글
Spring Security에서 Ajax post 방식 사용할 때 (0) | 2019.08.31 |
---|---|
form 태그의 th:action을 동적으로 바꾸는 방법 (0) | 2019.08.23 |
@PathVariable, URL에 파라미터 전달하기 (0) | 2019.08.20 |
오류 : cannot find symbol (0) | 2019.08.13 |
Spring security 적용해보자(1) (0) | 2019.08.12 |
Spring security CSRF 프로텍션 (0) | 2019.08.09 |
Spring JPA를 사용해 보자~ (0) | 2019.08.06 |
스프링 어노테이션 정리~ (0) | 2019.07.22 |