Spring(2023-04-18)

권단비·2023년 4월 18일
0

IT

목록 보기
124/139
post-thumbnail

[스프링 시큐리티]

・스프링 시큐리티(인증과 권한) = 인증과 권한을 위한 솔루션(프레임워크)

[*스프링 시큐리티 실행 순서]
1. pom.xml에 생성하자마자 스프링 시큐리티 객체 생성
2. Request객체를 낚아챔(Filter 기능 @EnableWebSecurity) : SecurityConfig.java 실행하여 URL체크 → 로그인 화면으로 넘어감 → 로그인까지
3. 인증 완료 후 Controller로 넘어감


[*스프링 시큐리티 특징과 구조]
	- 보안과 관련하여 체계적으로 많은 옵션을 제공하여 편리하게 사용할 수 있음
	- Filter기반으로 동작하여 MVC와 분리하여 관리 및 동작
	- 어노테이션을 통한 간단한 설정 Spring Security는
	- 기본적으로 세션 & 쿠키방식으로 인증

1) 인증과 권한
	- 인증(Authentication)=로그인
    * 인증 : 푸르덴셜타워 출입 시 사원증 찍음
    
    - 권한(인가)(Authorization) = 리소스 접근 제어
    * 권한(인가) : 각 부서에 출입 시 사원증 찍음
    
2) 암호화 모듈 제공

3) CSRF 방어 모듈 제공
・인증API
http.formLogin()
http.logout()
http.csrf()
http.httpBasic()

・인가API
http.authorizeRequests()
.antMatchers(/admin)
.hasRole(User)
- 접근 주체(Principal) : 보호된 리소스에 접근하는 대상 || 일반 유저
- 인증(Authentication) : 보호된 리소스에 접근한 대상이 누구인지
- 인가(Authorize) : 해당 리소스에 대해 접근 가능한 권한을 가지고 있는지 확인하는 과정(After Authentication, 인증 이후)
- 권한

・시큐리티 테이블

user(1)유저이름 : authorities권한이름(N)
시큐리티 파일 2개 줄테니까 
1. UserDetailsVO : user이름, password, 권한을 적어라
2. CustomUserDetailsService > SecurityConfig에서 받아옴

*Junit Test(UserMapper.java에서 오른쪽 클릭)


[계산 pom.xml]
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>2.6.8</version>
		<relativePath /> <!-- lookup parent from repository -->
	</parent>
	<groupId>edu.global</groupId>
	<artifactId>ex</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>spring_boot_kdb_security</name>
	<description>Board project for Spring Boot</description>
	<properties>
		<java.version>11</java.version>
	</properties>
	<repositories>
		<repository>
			<id>oracle</id>
			<url>http://www.datanucleus.org/downloads/maven2/</url>
		</repository>
	</repositories>

	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

		<!-- spring-boot-devtools는 클래스 수정시 웹서버를 재시작하여 결과를 바로 반영 -->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-tomcat</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

		<!-- 오라클 JDBC 드라이버 -->
		<dependency>
			<groupId>oracle</groupId>
			<artifactId>ojdbc6</artifactId>
			<version>11.2.0.3</version>
		</dependency>

		<!-- MyBatis 라이브러리 -->
		<dependency>
			<groupId>org.mybatis.spring.boot</groupId>
			<artifactId>mybatis-spring-boot-starter</artifactId>
			<version>2.1.4</version>
		</dependency>

		<!-- MyBatis sql pretty -->
		<dependency>
			<groupId>org.bgee.log4jdbc-log4j2</groupId>
			<artifactId>log4jdbc-log4j2-jdbc4.1</artifactId>
			<version>1.16</version>
		</dependency>

		<!-- JSP를 사용하기 위한 라이브러리 -->
		<!-- 톰캣 파서 -->
		<dependency>
			<groupId>org.apache.tomcat.embed</groupId>
			<artifactId>tomcat-embed-jasper</artifactId>
		</dependency>

		<!-- jstl 라이브러리 -->
		<dependency>
			<groupId>javax.servlet</groupId>
			<artifactId>jstl</artifactId>
		</dependency>
	</dependencies>

	<build><!-- 컴파일~배포까지 -->
		<plugins>
			<plugin>
				<groupId>org.apache.tomcat.maven</groupId>
				<artifactId>tomcat7-maven-plugin</artifactId>
				<version>2.2</version>
				<configuration>
					<url>http://146.56.137.240:8282/manager/text</url>
					<username>admin</username>
					<password>1234</password>
				</configuration>
			</plugin>
			<!-- cmd에 입력 ( 배포 ) : mvnw.cmd tomcat7:redeploy -->
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
				<configuration>
					<excludes>
						<exclude>
							<groupId>org.projectlombok</groupId>
							<artifactId>lombok</artifactId>
						</exclude>
					</excludes>
				</configuration>
			</plugin>
		</plugins>
	</build>
</project>
---------------------------------------------------------------------
[계산 application.properties]
#server port number
server.port = 8282

#datasource (oracle)
#spring.datasource.driver-class-name=oracle.jdbc.driver.OracleDriver
#spring.datasource.url=jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.driver-class-name=net.sf.log4jdbc.sql.jdbcapi.DriverSpy
spring.datasource.url=jdbc:log4jdbc:oracle:thin:@localhost:1521/xe
spring.datasource.username=scott
spring.datasource.password=tiger

spring.devtools.livereload.enabled=true

#MyBatis
#xml location
#src/main/resources/mappers
mybatis.mapper-locations=classpath:mappers/`**/*.xml
mybatis.type-aliases-package=edu.global.ex

#jsp 
spring.mvc.view.prefix=/WEB-INF/views/
spring.mvc.view.suffix=.jsp

#logging
#logging.level.root=info
---------------------------------------------------------------------
[계산 HomeController.java]
package edu.global.ex.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Controller
public class HomeController {

	@GetMapping("/")
	public String home() {
		return "home";
	}

	@GetMapping("/user/userHome")
	public void userHome() { // void는 return값이 없지만, userHome.jsp를 리턴함
		log.info("userHome ...");
	}
//상기 userHome함수는 하기와 동일한 의미이다.
//	@GetMapping("/user/userHome")
//	public String userHome() {
//		log.info("userHome ...");
//		return "user/userHome";
//	}

	@GetMapping("/admin/adminHome")
	public void adminHome() {
		log.info("adminHome ...");
	}
}
---------------------------------------------------------------------
[계산 SecurityConfig.java]
package edu.global.ex.config;
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;

@Configuration // @Component + 의미(설정할 수 있는 파일)//(객체 생성해서 IOC컨테이너에 넣어라)
@EnableWebSecurity // 스프링 시큐리티 필터가 스프링 필터체인에 등록됨 = 스프링 시큐리티를 작동시키는 파일이라는 것을 알려줌 - 스프링한테.
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private CustomUserDetailsService customUserDetailsService;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 우선 CSRF설정을 해제한다.
		// 초기 개발시만 해주는게 좋다.
		http.csrf().disable();
		http.authorizeRequests()
//	      .antMatchers("/user/**").hasAnyRole("USER") 
//	      .antMatchers("/admin/**").hasAnyRole("ADMIN")
//	      .antMatchers("/**").permitAll();
			.antMatchers("/**").hasAnyRole("ADMIN"); // id: admin, pw:admin

		http.formLogin(); // 스프링 시큐리티에 있는 기본 로그인 폼을 사용하겠다.
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.inMemoryAuthentication().withUser("user").password("{noop}user").roles("USER").and().withUser("admin")
				.password("{noop}admin").roles("ADMIN");
	}
}
---------------------------------------------------------------------
[계산 UserVO.java]
package edu.global.ex.vo;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class UserVO {
	private String username;
	private String password;
	private int enabled;

	private List<AuthVO> authList;
}
---------------------------------------------------------------------
[계산 AuthVO.java]
package edu.global.ex.vo;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;

@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class AuthVO {
	private String username;
	private String authority;
}
---------------------------------------------------------------------
[계산 UserMapper.java]
package edu.global.ex.mapper;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Mapper;
import edu.global.ex.vo.UserVO;

@Mapper // MyBatis용 인터페이스라는 것을 알려주는 어노테이션
public interface UserMapper {
	public UserVO getUser(String username);

	@Insert("insert into users(username,password,enabled) values(#{username},#{password},#{enabled})")
	public int insertUser(UserVO userVO);

	@Insert("insert into AUTHORITIES (username,AUTHORITY) values(#{username},'ROLE_USER')")
	public void insertAuthorities(UserVO UserVO);
}
---------------------------------------------------------------------
[계산 UserMapper.xml]
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
   PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
   "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="edu.global.ex.mapper.UserMapper">

	<resultMap id="userMap" type="UserVO">
		<result property="username" column="username" />
		<result property="password" column="password" />
		<result property="enabled" column="enabled" />
		<collection property="authList" resultMap="authMap"></collection>
	</resultMap>

	<resultMap id="authMap" type="AuthVO">
		<result property="username" column="username" />
		<result property="authority" column="authority" />
	</resultMap>

	<select id="getUser" resultMap="userMap">
		<!-- 조인 처리 -->
		select * from users , authorities
		where users.username = authorities.username and users.username = #{username}
	</select>
</mapper>
---------------------------------------------------------------------
[계산 UserDetailsVO.java]
package edu.global.ex.vo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

public class UserDetailsVO implements UserDetails { // DB와 연결 || ID/PW/Authority를 가져와 연결
	private String username; // ID
	private String password; // PW
	private List<GrantedAuthority> authorities;

	public UserDetailsVO(UserVO user) {
		this.setAuthorities(user);
		this.setPassword(user.getPassword());
		this.setUsername(user.getUsername());
	}

	// setter
	public void setUsername(String username) {
		this.username = username;
	}

	// setter
	public void setPassword(String password) {
		this.password = password;
	}

	// setter
	public void setAuthorities(UserVO userVO) {

		List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

		for (AuthVO auth : userVO.getAuthList()) {
			authorities.add(new SimpleGrantedAuthority(auth.getAuthority()));
		}

		this.authorities = authorities;
	}
	// ==============================================================================
	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return authorities;
	}

	@Override
	public String getPassword() {
		return password;
	}

	@Override
	public String getUsername() {
		return username;
	}

	// 계정이 만료되지 않았는가?
	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	// 계정이 잠기지 않았는가?
	@Override
	public boolean isAccountNonLocked() {
		return true;
	}

	// 패스워드가 만료되지 않았는가?
	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	// 계정이 활성화 되었는가?
	@Override
	public boolean isEnabled() {
		return true;
	}
}
---------------------------------------------------------------------
[계산 CustomUserDetailsService.java]
package edu.global.ex.security;
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;
import edu.global.ex.mapper.UserMapper;
import edu.global.ex.vo.UserDetailsVO;
import edu.global.ex.vo.UserVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Service
public class CustomUserDetailsService implements UserDetailsService {

	@Autowired
	private UserMapper userMapper;

	@Override
	public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		log.warn("Load User By UserVO number: " + username);
		UserVO vo = userMapper.getUser(username);

		log.warn("queried by UserVO mapper: " + vo);

		return vo == null ? null : new UserDetailsVO(vo);
	}
}
---------------------------------------------------------------------
[계산 UserMapperTest.java] : Junit Test(UserMapper.java 우측 클릭)
package edu.global.ex.mapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import edu.global.ex.vo.UserVO;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@SpringBootTest
class UserMapperTest {

	@Autowired
	private UserMapper userMapper;

	@Test
	void testInserUser() {

//      @Insert("insert into users(username,password,enabled) values(#{username},#{password},#{enabled})")
//      public int insertUser(UserVO userVO);
//
//      @Insert("insert into AUTHORITIES (username,AUTHORITY) values(#{username},'ROLE_USER')")
//      public void insertAuthorities(UserVO UserVO);

		UserVO user = new UserVO();
		user.setUsername("kim2");
		user.setPassword(new BCryptPasswordEncoder().encode("kim2"));
		user.setEnabled(1);

		userMapper.insertUser(user);
		userMapper.insertAuthorities(user);
	}
}
---------------------------------------------------------------------
[계산 home.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<img src="/img/bye.gif">
</body>
</html>
---------------------------------------------------------------------
[계산 adminHome.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>관리자(어드민) 페이지입니다.</h1>
</body>
</html>
---------------------------------------------------------------------
[계산 userHome.jsp]
<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<body>
<h1>유저 페이지입니다.</h1>
</body>
</html>
[결과값]

localhost:8282/user/userHome

localhost:8282/admin/adminHome


[DB설계]

[시퀀스 다이어그램]

시간 순서

[유스케이스 다이어그램]

구성요소(Component)

1) 시스템(System)
만들고자 하는 프로그램을 나타낸다

2) 액터(Actor)
시스템의 외부에 있고 시스템과 상호작용을 하는 사람(시스템의 기능을 사용하는 사람), 시스템(시스템에 정보를 제공하는 또 다른 시스템)을 말한다.

3) 유스케이스(Usecase)
사용자 입장에서 바라본 시스템의 기능
시스템이 액터에게 제공해야 하는 기능으로 시스템의 요구사항을 나타낸다.

-표기
타원으로 표시하고 안쪽에 유스케이스명을 작성한다.
유스케이스명은 "~한다"와 같이 동사로 표현한다.

4) 관계(Relation)
1)포함 관계(필수적으로 요구) : login된 상태에서만 include표시

2)확장 관계(선택적 관계:특정 조건이 만족될경우) : 글을 첨부하는데 파일을 첨부해도 되고 안 해도 된다.

3)일반화 관계(Generalization) - 추상화

0개의 댓글