Ex) 초기 설정
- 먼저, 관리자 페이지를 구성한다. ex)admin,backoffice, cms가 들어간다. http://admin.fastlms.co.kr
- 서브 도메인을 따로 둘 수도 있다. http://www.fastlms.co.kr/admin
- adminService를 만든다. (member쪽을 만들었듯이)
-> AdminMainController
<hide/>
package com.zerobase.fastlms.admin;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AdminMainController {
@GetMapping("/admin/main.do")
public String main(){
return "admin/main";
}
}
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 확인</title>
</head>
<body>
<h1>관리자 메인 화면</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
</body>
</html>
- Security 클래스에 permitAll()로 등록되어 있지 않아서 로그인한 다음에야 admin/main 페이지에 접속이 가능하다.
========================================= 오류 ==========================================
- 오류: 로그인 안해도 바로 관리자 화면이 뜬다.
- 원인: ?
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 확인</title>
</head>
<body>
<h1>관리자 메인 화면</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
<div>
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
<br>
</div>
</body>
</html>
- AdminMemberController
<hide/>
package com.zerobase.fastlms.admin;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
@Controller
public class AdminMemberController {
@GetMapping("/admin/member/list.do")
public String list(){
return "admin/member/list";
}
}
- list 파일 만든다.
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>관리자 화면</title>
</head>
<body>
<h1>관리자 회원 관리</h1>
<!-- <div th:replace="/fragments/layout.html :: fragment-body-menu" ></div>-->
<div>
<a href="/admin/main.do">관리자 메인</a>
|
<a href="/admin/member/list.do">회원 관리</a>
|
<a href="#">카테고리 관리</a>
|
<a href="#">강의 관리</a>
|
<a href="/member/logout">로그 아웃</a>
<br>
</div>
</body>
</html>
- 위 화면에서 로그아웃 누르면?
Ex) 관리자 권한과 사용자 권한을 구분하려면?
- Entity에 필드 추가 - 관리자인지 회원인지 여부를 나타낸다.
<hide/>
package com.zerobase.fastlms.member.entity;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import javax.persistence.Entity;
import javax.persistence.Id;
import java.time.LocalDateTime;
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Data // getter, setter
@Entity
public class Member {
@Id
private String userId;
private String userName;
private String phone;
private String password;
private LocalDateTime regDt;
private boolean emailAuthYn;
private LocalDateTime emailAuthDt;
private String emailAuthKey;
private String resetPasswordKey;
private LocalDateTime resetPasswordLimitDt; //초기화 가능한 날짜
// 관리자 여부를 지정할 것인지 여부
// 회원에 따른 ROLE을 지정할 것인가?
// 준회원 / 정회원 / 특별회원/ 관리자
// ROLE_SEMI_USER, ROLE_USER, ROLE_SPECIAL_USER, ROLE_ADMIN
//
private boolean adminYn; // 관리자 여부
}
cf) yml 파일에 jpa 설정이 있기 때문에 엔티티에 데이터를 추가하면 DDL을 자동 생성하고 데이터베이스까지 저장한다.
- 데이터베이스에 저장된 계정 중 하나를 관리자 user(true)로 만든다.
Ex) 회원 가입 후, 이메일이 활성화 되는 것은 한 번만 가능하도록 수정
- Impl 클래스
-> 회원 가입했을 때 받은 회원 가입 메일의 링크를 들어가면 활성화 페이지가 보인다. 이는 한 번만 가능해야한다.
-> 따라서 impl클래스를 수정한다. (여러 번 활성화되지 않도록한다.)
- impl - emailAuth()메서드를 수정한다.
<hide/>
@Override
public boolean emailAuth(String uuid) { // 이메일 인증
Optional<Member> optionalMember = memberRepository.findByEmailAuthKey(uuid); // 있으면 Optional<Member> 가 리턴된다.
if(!optionalMember.isPresent()){
return false;
}
Member member = optionalMember.get(); // 존재하는 경우 멤버
// 이미 활성화됐기 때문에 또 활성화할 필요없다.
if(member.isEmailAuthYn()){
return false;
}
member.setEmailAuthYn(true);
member.setEmailAuthDt(LocalDateTime.now());
memberRepository.save(member);
return true;
}
Note) 실행 결과
- 아래처럼 실패라고 나와야 정상이다.
Ex)
- loadUserByUserName() 메서드에서 user가 관리자인 경우는?
-> "ROLE_ADMIN"을 추가한다.
-> SimpleGrantedAuthority("ROLE_USER"): GrantedAuthority 인터페이스를 구현한 클래스이다.
<hide/>
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { // 실질적으로 이메일
Optional<Member> optionalMember = memberRepository.findById(username);
if(!optionalMember.isPresent()){
throw new UsernameNotFoundException("회원 정보가 존재하지 않습니다.");
}
Member member = optionalMember.get();
if(!member.isEmailAuthYn()){
throw new MemberNotEmailAuthException("이메일 활성화 이후에 로그인 해주세요");
}
List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
// 추가 - 관리자 ROLE
if(member.isAdminYn()){
grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}
return new User(member.getUserId(), member.getPassword(), grantedAuthorities); // role
}
- SecurityConfig에 관리자 권한 관련해서 내용을 추가한다.
-> AntPathRequestMatcher(String pattern): 대소문자를 구분하지 않고 모든 http 메서드와 일치하는 특정 패턴으로 Matcher을 만든다.
<hide/>
package com.zerobase.fastlms.configuration;
import com.zerobase.fastlms.member.service.MemberService;
import lombok.RequiredArgsConstructor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
@RequiredArgsConstructor
@EnableWebSecurity
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
private final MemberService memberService;
@Bean
PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
@Bean
UserAuthenticationFailureHandler getFailureHandler(){
return new UserAuthenticationFailureHandler();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // csrf: 토큰
http.authorizeRequests()
.antMatchers(
"/"
, "/member/register"
, "/member/email-auth"
, "/member/find-password"
// , "/member/reset/password"
// , "/admin"
)
.permitAll();
// 추가 - 관리자 권한
http.authorizeRequests()
.antMatchers("/admin/**")
.hasAnyAuthority("ROLE_ADMIN");
http.formLogin()
.loginPage("/member/login")
.failureHandler(getFailureHandler())
.permitAll();
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
.logoutSuccessUrl("/") // 로그아웃 성공하면 메인페이지 이동
.invalidateHttpSession(true); // 로그아웃했으니 새션 초기화
super.configure(http);
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(memberService)
.passwordEncoder(getPasswordEncoder());
super.configure(auth);
}
}
- 관리자가 아닌 일반 계정으로 로그인
- 다음과 같이 관리자 페이지를 들어가려고 시도하면 오류가 난다. => 추가 작업을 한다.
- 관리자 계정 접속: 관리자 메인 화면 접속 가능
- 일반계정 처리 작업
-> SecutiryConfig 클래스 수정
-> logoutSuccessUrl("/"): 로그아웃을 성공하면 메인 페이지로 이동한다.
-> invalidateHttpSession(true): 로그아웃 했으니까 세션을 초기화한다.
<hide/>
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable(); // csrf: 토큰
http.authorizeRequests()
.antMatchers(
"/"
, "/member/register"
, "/member/email-auth"
, "/member/find-password"
// , "/member/reset/password"
// , "/admin"
)
.permitAll();
http.authorizeRequests()
.antMatchers("/admin/**")
.hasAnyAuthority("ROLE_ADMIN");
http.formLogin()
.loginPage("/member/login")
.failureHandler(getFailureHandler())
.permitAll();
http.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/member/logout"))
.logoutSuccessUrl("/") // 로그아웃 성공하면 메인페이지 이동
.invalidateHttpSession(true); // 로그아웃했으니 새션 초기화
// 추가 - 접근 제한
http.exceptionHandling()
.accessDeniedPage("/error/denied");
super.configure(http);
}
- 메인 컨트롤러에 추가
<hide/>
@RequestMapping("/error/denied")
public String errorDenied() {
return "error/denied";
}
- denied 파일 추가한다.
<hide/>
<!doctype html>
<html lang="ko" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>에러 페이지</title>
</head>
<body>
<h1>에러 페이지</h1>
<p>접근 권한이 없습니다.</p>
<div>
<a href="/" >홈으로 이동</a>
</div>
</body>
</html>
Note) 회원이 관리자 페이지에 접근하는 경우 - 실행 결과
'Spring Projcect > 학습 관리 시스템 & 백오피스 구축' 카테고리의 다른 글
Chapter 11. 회원 상세 및 상태 처리 (0) | 2022.08.21 |
---|---|
Chapter 10. 회원 목록 (0) | 2022.08.20 |
Chapter 08. 스프링 부트 프로젝트 - 비밀번호 찾기(초기화) (0) | 2022.08.18 |
Chapter 07. 스프링 부트 프로젝트 - 로그인/로그아웃 (0) | 2022.08.18 |
Chapter 05. 스프링부트 기반 웹 프로젝트 구성 (0) | 2022.08.09 |