스프링 시큐리티
- 홈화면(로그인 전에)
127.0.0.1:9090/ROOT/security_home
127.0.0.1:9090/ROOT/member/security_join
127.0.0.1:9090/ROOT/member/security_login
- 관리자 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_admin/home
127.0.0.1:9090/ROOT/security_admin/insert
- 판매자 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_seller/home
127.0.0.1:9090/ROOT/security_seller/item
- 고객 홈화면(로그인 후에)
127.0.0.1:9090/ROOT/security_customer/home
127.0.0.1:9090/ROOT/security_customer/mypage
파일명 pom.xml
<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
파일명 SecurityController.java
package com.example.controller;
import com.example.dto.MemberDTO;
import com.example.dto.MyUserDTO;
import com.example.mapper.MemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
@Controller
public class SecurityController {
@Autowired MemberMapper mMapper;
@GetMapping(value = {"/security_403"})
public String security403GET(){
return "/security/403page";
}
// 로그인과 상관없이 보여지는 홈화면
// 127.0.0.1:9090/ROOT/security_home
@GetMapping(value = {"/security_home"})
public String securityhomeGET(
Model model,
@AuthenticationPrincipal MyUserDTO user
){
if(user != null){
System.out.println(user.getName());
System.out.println(user.getUserphone());
System.out.println(user.getUsername());
System.out.println(user.getAuthorities().toArray()[0]);
}
model.addAttribute("user",user);
// model.addAttribute("userid",user.getUsername());
// model.addAttribute("userrole",user.getAuthorities().toArray()[0]);
return "/security/home";
}
// 관리자 로그인후에 보여지는 홈화면
// 127.0.0.1:9090/ROOT/security_asmin/home
@GetMapping(value = {"/security_admin/home"})
public String securityAdminhomeGET(){
return "/security/admin_home";
}
// 판매자 로그인후에 보여지는 홈화면
// 127.0.0.1:9090/ROOT/security_seller/home
@GetMapping(value = {"/security_seller/home"})
public String securitySellerhomeGET(){
return "/security/seller_home";
}
// 고객 로그인후에 보여지는 홈화면
// 127.0.0.1:9090/ROOT/security_customer/home
@GetMapping(value = {"/security_customer/home"})
public String securityCustomerhomeGET(){
return "/security/customer_home";
}
// 127.0.0.1:9090/ROOT/customer/security_join
@GetMapping(value = "/member/security_join")
public String securityJoinGET(){
return "/security/join";
}
@PostMapping(value = "/member/security_join")
public String SecurityJoinPOST(
@ModelAttribute MemberDTO member
){
BCryptPasswordEncoder bcpe = new BCryptPasswordEncoder();
// 암호를 가져와서 해시한후 다시 추가하기
member.setUpw(bcpe.encode(member.getUpw()));
member.setUrole("CUSTOMER");
int ret = mMapper.memberJoin(member);
if(ret ==1){ // 성공시
return "redirect:/security_home";
}
// 실패시
return "redirect:/member/security_join";
}
@GetMapping(value="/member/security_login")
public String securityLoginGET(){
return "/security/login";
}
}
파일명 SecurityConfig.java
package com.example.config;
import com.example.service.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
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;
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
// 1. 직접 만든 detailService 객체 가져오기
@Autowired
UserDetailsServiceImpl detailsService;
// 회원가입시 암호화 했던 방법의 객체생성
// 2. 암호화 방법 객체 생성, @Bean은 서버 구동시 자동으로 객체 생성됨
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
// 3. 직접만든 detailsService에 암호화 방법 적용
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(detailsService)
.passwordEncoder( bCryptPasswordEncoder() );
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);
// 페이지별 접근 권한 설정
http.authorizeRequests()
.antMatchers("/admin","/admin/**")
.hasAuthority("ADMIN")
.antMatchers("/seller","/seller/**")
.hasAnyAuthority("ADMIN", "SELLER")
.antMatchers("/customer","/customer/**")
.hasAuthority("CUSTOMER")
.anyRequest().permitAll();
// 로그인 페이지 설정, 단 POST는 직접 만들지 않음
http.formLogin()
.loginPage("/member/login")
.loginProcessingUrl("/member/loginaction")
.usernameParameter("uemail")
.passwordParameter("upw")
.defaultSuccessUrl("/home")
.permitAll();
// 로그아웃 페이지 설정, url에 맞게 POST로 호출하면 됨.
http.logout()
.logoutUrl("/member/logout")
.logoutSuccessUrl("/home")
//.logoutSuccessHandler(new MyLogoutSuccessHandler())
.invalidateHttpSession(true)
.clearAuthentication(true)
.permitAll();
// 접근권한불가 403
http.exceptionHandling().accessDeniedPage("/page403");
// h2-console을 사용하기 위해서
http.csrf().ignoringAntMatchers("/h2-console/**");
http.headers().frameOptions().sameOrigin();
http.csrf().ignoringAntMatchers("/api/**");
}
}
파일명 MemberMapper.java
package com.example.mapper;
import com.example.dto.MemberDTO;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;
@Mapper
public interface MemberMapper {
// 회원가입
// INSERT INTO 테이블명(컬럼명들) VALUES(추가할 값들)
@Insert({
"INSERT INTO MEMBER( UEMAIL, UPW, UNAME, UPHONE, UROLE, UREGDATE )",
" VALUES( #{ obj.uemail }, #{ obj.upw }, #{ obj.uname }",
" , #{ obj.uphone }, #{ obj.urole }, CURRENT_DATE ) "
})
public int memberJoin( @Param(value = "obj") MemberDTO member);
// 로그인
// SELECT 컬럼명들 FROM 테이블명 WHERE 조건 AND 조건
@Select({
"SELECT UEMAIL, UNAME, UROLE FROM MEMBER WHERE UEMAIL = #{email} AND UPW = #{pw}"
})
public MemberDTO memberLogin(
@Param(value = "email") String em,
@Param(value = "pw") String userpw);
// security 로그인
// SELECT 컬럼명들 FROM 테이블명 WHERE 조건
@Select({
"SELECT UEMAIL, UPW, UROLE, UPHONE, UNAME FROM MEMBER WHERE UEMAIL = #{email}"
})
public MemberDTO memberEmail(
@Param(value = "email") String em);
}
파일명 MemberDetailServiceImpl.java
package com.example.service;
import java.util.Collection;
import com.example.dto.MemberDTO;
import com.example.dto.MyUserDTO;
import com.example.mapper.MemberMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
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;
@Service
public class MemberDetailServiceImpl implements UserDetailsService {
@Autowired MemberMapper mMapper;
// 로그인에서 입력하는 정보중에서 아이디를 받음
// MemberMapper를 이용해서 정보를 가져와서 UserDetails로 리턴
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("MemberDetailService : "+ username);
MemberDTO member = mMapper.memberEmail(username);
// 권한정보를 문자열 배열로 만듬
String[] strRole = {member.getUrole()};
// String 배열 권한을 Collection<GrantedAuthority>로 변환함
Collection<GrantedAuthority> roles = AuthorityUtils.createAuthorityList(strRole);
// 아이디, 암호, 권한들...리턴
// User user = new User(member.getUemail(),member.getUpw(), roles);
MyUserDTO user = new MyUserDTO(member.getUemail(), member.getUpw(), roles, member.getUphone(), member.getUname());
return user;
}
}
파일명 MyUserDTO.java
package com.example.dto;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper=false)
public class MyUserDTO extends User {
private static final long serialVersionUID = 1L;
private String username = null;
private String password = null;
private String userphone = null;
private String name = null;
public MyUserDTO(
String username,
String password,
Collection<? extends GrantedAuthority> authorities,
String userphone,
String name) {
super(username, password, authorities);
this.username = username;
this.password = password;
this.userphone = userphone;
this.name = name;
}
}
파일명 MyLoginSuccessHandler.java
package com.example.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
// 로그인 성공했을 때 자동으로 호출되는 handler
public class MyLoginSuccessHandler implements AuthenticationSuccessHandler{
@Override
public void onAuthenticationSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication) throws IOException, ServletException {
System.out.println("LoginSuccessHandler");
User user = (User)authentication.getPrincipal();
// System.out.println(authentication.getPrincipal());
System.out.println(user.toString());
// System.out.println(authentication.getAuthorities().toArray()[0]);
String role = (String)authentication.getAuthorities().toArray()[0].toString();
System.out.println(role);
if(role.equals("ADMIN")){
response.sendRedirect( request.getContextPath() + "/security_admin/home");
}
else if(role.equals("SELLER")){
response.sendRedirect(request.getContextPath() + "/security_seller/home");
}
else if(role.equals("CUSTOMER")){
response.sendRedirect(request.getContextPath() + "/security_customer/home");
}
}
}
파일명 MyLogoutSuccessHandler.java
package com.example.handler;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
public class MyLogoutSuccessHandler implements LogoutSuccessHandler{
@Override
public void onLogoutSuccess(
HttpServletRequest request,
HttpServletResponse response,
Authentication authentication)
throws IOException, ServletException {
response.sendRedirect( request.getContextPath() + "/security_home");
}
}