학원/SPRING

12/29 72-3 [SPRING] Security_1

도원결의 2022. 12. 29. 21:45

 

 

오늘 하는 것 들다 멘붕이였는데

이게 젤 최고로 멘붕인거 같다..

와....

뭘 안빼먹으면 그나마 다행....

 

이거 왜 필요함?

진짜 보안을 위해서 필요함..

로그인 여부 판단 하는 거

게시판 했을 때는 일일이 페이지 마다 넣어가면서 걸러 냈는데

그 역할을 한방에 해주는게 security  인 것 같음

 

그래

이거도... 관련 라이브러리를 먼저 넣어 놓자..

<!-- 스프링 씨큐리티 관련 라이브러리 -->
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-web</artifactId>
    <version>4.2.20.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-config</artifactId>
    <version>4.2.20.RELEASE</version>
</dependency>		
<dependency>
    <groupId>org.springframework.security</groupId>
    <artifactId>spring-security-taglibs</artifactId>
    <version>4.2.20.RELEASE</version>
</dependency>

 

역시 등록을 해야겠지 ! 이제 이정도면 외우겠다 싶었는데

얘는 조오큼 뭔가 내용도 많고 뭔가 곱씹어야 함...

참고로 요거 등록은 

1. web.xml 에다가  xml 기반으로 등록하는 방법도 해보고 

2.어노테이션 기반 씨큐리티 설정하는 방법도 해봄 ,,,  (와 내가 언제그걸 했지....)

 

1.xml 기반 등록(어차피 주석처리할 거라 간단하게 필요했던 것만 정리할 거)

xml 기반이니까 web.xml 가서 먼저 등록

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/spring/root-context.xml</param-value>
</context-param>

그러면 securityConfig.java는 이렇게 등록하지요

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	//인증 및 접근제한 등을 설정(authention)
	@Override
	protected void configure(HttpSecurity http) throws Exception {
/*
		 * super.configure(http);
		 * 위 메소드의 구현 내용
		 * http
			.authorizeRequests()   //요청에 대해 시큐리티 인증을 시작하겠음
			.anyRequest().authenticated()   //어떤 요청이든지 권한이 있어야 함
			.and()  
			.formLogin()     //폼기반의 인증을 하겠음
			.and()
			.httpBasic();  //http기본인증을 사용하겠음
			여기까진 설명이고 밑에가 진짜 코드 
*/     
		
		//스프링 씨큐리티 기본 테스트	
		http
			.authorizeRequests()   
			.anyRequest().authenticated()
			.and()
			.formLogin()
			.and()
			.csrf().disable(); //여기가 좀 다르네! csrf보안 비 활성화		
		}/////
}

 

근데 최종적으로는 이렇게 안함!!! 저거 다 주석처리  해야 해 !!

 

2.어노테이션 기반 씨큐리티 설정하는 방법

web.xml

 

 

 <!-- 2.자바코드(어노테이션 기반)로 설정하기 위한 컨텍스트 파라미터 등록 
		 xml이아닌 어노테이션 기반의 자바코드로 설정하기 위한 파라미터 -->
	 <context-param>
	 	<param-name>contextClass</param-name>
		<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
	 </context-param>
	 <!-- 3. 스프링씨큐리티 자바코드로 설정한 클래스를 컨텍스트 초기화 파라미터로 등록 -->
	 <context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>com.kosmo.springapp.basic.security.SecurityConfig</param-value>
	</context-param>
	<!-- 4.스프링 씨큐리티용 필터 등록(필터명은 반드시 springSecurityFilterChain) -->
	<filter>
		<filter-name>springSecurityFilterChain</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
	</filter>
	<filter-mapping>
		<filter-name>springSecurityFilterChain</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>​

SecurityConfig.java 에는요렇게!

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	
	//인증 및 접근제한 등을 설정(authention)
	@Override
	protected void configure(HttpSecurity http) throws Exception {

		http
			.authorizeRequests()
			//**에대한 설명은 : https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/util/AntPathMatcher.html
			.antMatchers("/onememo/bbs/**").hasRole("USER") //여기서는 ROLE_는 반드시 생략! 자동으로 추가 됨
			.anyRequest().permitAll() //모든요청에 대해 권한 인증 없이 처리하게따!!!  
			.and() //HttpSecurity 반환
			.formLogin()
			.loginPage("/onememo/auth/Login.do")  //내가만든 로그인 폼 url로 설정, 기본값은 "/login"
			.loginProcessingUrl("/onememo/auth/LoginProcess.do") //폼의 action속성값. 실제 로그인 처리는 씨큐리티가 진행한다... wow! 그러니 컨트롤러에 로그인처리부분만들필요 없음 
			.failureUrl("/onememo/auth/Login.do") //로그인 실패 시 보여질 페이지 설정, "login?error"이 기본값
			.usernameParameter("id") //로그인 폼에 아이디 입력 필드에 지정한 name 속성값. 기본값은 "username"
			.passwordParameter("pwd")//로그인 폼에 패스워드 입력 필드에 지정한 name 속성값. 기본값은 "password"
			.defaultSuccessUrl("/",true)//인증 성공 후 이동 할 url설정, 보호된 페이지를 이전에 방문한 적이 있더라도 인증하려면 true
			.and()
			.logout()//로그아웃 URL지정. 안해도 된대 와....,실제 로그아웃 처리는 씨큐리티가 진행 "/logout" 디폴트 
			.and()
			.csrf().disable()
			/*
			CSRF(Cross Site Resquest Fosery) 공격을 방어하기 위한 설정
				CSRF방어 설정시에는  사용자 정의 로그인 폼 사용 시에
				아래 hidden태그 필수(post방식인 경우)***
				<input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
				또한 로그아웃을 POST 방식으로 해야 한다. 
				CSRF 방어를 사용하지 않도록 되어있다면 GET 방식으로도 처리가능하다
				예]
					<form:form action="<c:url value='/logout'/>" method="POST">
						<input type="submit" value="로그아웃" />
					</form:form>  */
			//중복로그인 방지를 위한 설정
			.sessionManagement()
			.invalidSessionUrl("/onememo/auth/Login.do")//세션 끊어졌을 때 이동할 URL지정 . 중복일 때도 해당
			.maximumSessions(1) //최대 허용 가능 중복 세션 수.(중복 로그인 방지하기 위해 1로 설정)
		//  .maxSessionsPreventsLogin(true)
			.expiredUrl("/onememo/auth/Login.do");//세션 만기 시 이동할 URL 
	}
	
	//
	//사용자의 Authorization 설정(메모리 기반 혹근 JDBC기반 혹은 UserDetailsService 구현OK)
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/*	
	   //메모리 기반 인증(이건 하드코딩이고)
		auth
		.inMemoryAuthentication()
		.withUser("kosmo").password("1234").roles("USER")
		.and()
		.withUser("spring").password("1234").roles("ADMIN","USER");
	}////
*/					
		//JDBC기반 인증 사용(데이터베이스에 연결 해야지)
		auth
		 .jdbcAuthentication()
		 .dataSource(hikariDataSource())
		 .usersByUsernameQuery("select id as username, pass as password, enabled from users where id = ?")
		 .authoritiesByUsernameQuery("select id as username, authority from users where id = ?")
		 .passwordEncoder(passwordEncoder());
		}/////////
	
	//org.springframework.security.crypto.password.PasswordEncoder; 요거얌
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}  
	
	@Bean
	public HikariDataSource hikariDataSource() {
		HikariConfig hikariConfig = new HikariConfig();
		hikariConfig.setDriverClassName("oracle.jdbc.OracleDriver");
		hikariConfig.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:xe");
		hikariConfig.setUsername("SPRING");
		hikariConfig.setPassword("SPRING");
		return new HikariDataSource(hikariConfig);
	}
	
}

히카리 등록을 여기서 하고 기존에 등록 했던 곳에다가는 주입을 할 것임 !!

datatbaseConfig.java엔 요거만 남겨놓고 나머지 가져온거임

@Autowired
private HikariDataSource hikariDataSource;

잠시 나가 갈 방향을 보고 다시 가보자 

 

위 클래스 작성 후 해야할 작업들 순서
1. AuthController.java의 서비스 주입 및 로그인 처리 및 로그아웃 처리 주석
2. Login.jsp의 로그인 폼의 action속성을 반드시
   loginProcessingUrl()메소드에 지정한 경로와 일치 시켜야한다
3. Login.jsp의 세션영역에서 ${sessionScope.id}를 읽어오는 부분을
   모두 security 태그 라이브러를 사용해서 변경한다.
4. Top.jsp도 3번과 같이 security 태그 라이브러를 사용해서 변경
5. .java(컨트롤러)에서 세션영역에서 읽어오는 코드(@ModelAttribue String id)를 모두 Autentication API를 
      사용한 코드로 변경
   (@SessionAttribute나 HttpSesion등은 주석처리)
 

 

오늘 다 는 못 끝냈고...

내일 나머지 한다고 하심

근데 !! 

AuthController.java 랑 MemoController.java 에서

@SessionAttributes랑 

로그인 폼으로 이동 하는 메소드만 남겨놓고 모두 싹 다 주석 처리!

해놓음 !

그리고 

ONEMEMO에적용하기 위해  회원가입용 DAO도 생성

OnememoDAO.java 에 추가!

public int saveUser(Map<String, String> map) {
    return template.insert("saveUser",map);
}

er마스터로 테이블 생성 해야하는데 이거 까묵었었다 !!

만들어만들

 

 

onememeo.myvatis.mapper 에 쿼리문 등록

<!-- 스프링 씨큐리티 회원 입력용 -->
<insert id="saveUser" parameterType="Map" >
    INSERT INTO users VALUES(#{id},#{pass},#{name},DEFAULT,'ROLE_ADMIN')
</insert>

 

 

 

 

 

UserRestController.java생성 

소금치는 거 잘 봐두쟈

소금소금 !!!

@RestController
public class UsersRestController {

	@Autowired
	private OneMemoDAO dao;
	
	@Autowired
	private PasswordEncoder passwordEncoder;
    
	@PostMapping("/users.do")
	private Map insertUser(@RequestBody Map<String,String> map) {
		
		//사용자가 입력한 비밀번호를 암호화
		String rawPassword=map.get("pass");
		String encodedPassword=passwordEncoder.encode(rawPassword); //원문을 암호화 , 같은 비밀번호라도 암호화 할 땐 다르게 해야 함 ! (이게 소금 치는거래,, 소금이 랜덤하게 생성되기 때문에 같은게 나올 수 없대) 
		
		//암호화 된 비밀번호로 다시 설정
		map.put("pass", encodedPassword);
		System.out.println("비밀번호 원문:"+rawPassword);
		System.out.println("암호화 된 비밀번호:"+encodedPassword);
		System.out.println("암호 일치여부 판단"+passwordEncoder.matches(rawPassword, encodedPassword));
		int affected = dao.saveUser(map);
		
		System.out.println(affected+"행이 입력 되었습니다.");
		return map;				
	}
	
}

 

 

그리고 전에 구글에다가 즐겨 찾기 해놓은 talend사용해서 잘 적용 되는지 확인 함

 

200뜨면 성공!!
콘솔창에도 잘~ 나옴

 

아... 집갈래...