Spring 09 (23.04.18)

Jane·2023년 4월 18일
0

IT 수업 정리

목록 보기
107/124

1. Spring Security 개요

  • 인증 (Authentication) : 사용자의 신원을 검증, 패스워드 입력, 로그인
  • 인가 (Authorization) : 사용자에게 특정 리소스나 기능에 액세스할 수 있는 권한 부여
  • 접근 주체 (Principal) : 보호된 리소스에 접근하는 주체
  • 사용자가 서버에 접속할 때, 리퀘스트를 가로챈다. (인증 관리자, 접근 권한 관리자)

  • 구현 방법 : Filter 기반 동작, 쿠키와 세션 방식으로 인증

2. Spring Security 작업하기

HomeController.java (유저, 어드민에 대한 함수 추가)

	@GetMapping("/user/userHome")
	public void user_home() {
		log.info("userHome ...");
	}
	
	@GetMapping("/admin/adminHome")
	public void admin_home() {
		log.info("adminHome ... ");
	}
  • void로 데이터 타입을 주면 Mapping한 주소를 return 한다.
  • jsp : adminHome, userHome 만들어준다.

SecurityConfig.java (configure 수정 - 권한 부여)

@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable(); // CSRF 설정 해제 (초기 개발시 꺼놓고 작업)

		http.authorizeRequests()
				.antMatchers("/user/**").hasAnyRole("USER")
				.antMatchers("/admin/**").hasAnyRole("ADMIN");

		http.formLogin();
	}

SecurityConfig.java (내용 변경)

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable(); // CSRF 설정 해제 (초기 개발시 꺼놓고 작업)

		http.authorizeRequests()
				.antMatchers("/user/**").hasAnyRole("USER")
				.antMatchers("/admin/**").hasAnyRole("ADMIN")
				.antMatchers("/**").permitAll();

		http.formLogin();
	}
  • src/main/resource > static 폴더에 img 폴더 만들고, 사진을 home.jsp에 설정

3. 유저 정보 관리

3-1. 설정

  • 시큐리티 설명 파일 추가

  • SQL 파일을 Developers에 내용 넣고 실행

create table users(
	username varchar2(50) not null primary key,
	password varchar2(100) not null,
	enabled char(1) DEFAULT '1'
);
create table authorities (
	username varchar2(50) not null,
	authority varchar2(50) not null,
	constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

commit;

insert into users (username,password) values('user','user');
insert into users (username,password) values('member','member');
insert into users (username,password) values('admin','admin');

commit;

insert into AUTHORITIES (username,AUTHORITY) values('user','ROLE_USER');
insert into AUTHORITIES (username,AUTHORITY) values('member','ROLE_MANAGER');
insert into AUTHORITIES (username,AUTHORITY) values('admin','ROLE_MANAGER');
insert into AUTHORITIES (username,AUTHORITY) values('admin','ROLE_ADMIN');

commit;
  • users, authorities 테이블 생성

3-2. DB 내용 생성하기

  • UserVO, AuthVO 생성한다

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;

@AllArgsConstructor
@NoArgsConstructor
@Setter
@Getter
@ToString
public class AuthVO {
	private String username;
	private String authority;
}
  • application.properties에 mybatis 내용 추가
# MyBatis 
#xml location
mybatis.mapper-locations=classpath:mappers/**/*.xml
mybatis.type-aliases-package=edu.global.ex
  • Mapper 생성

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
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);
}
  • resource 밑에 mappers 폴더 생성 후 xml 작성하기

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>
  • getUser의 username 확인 : user, admin, member

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 {

	private String username;
	private String password;
	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() {
		// TODO Auto-generated method stub
		return authorities;
	}

	@Override
	public String getUsername() {
		// TODO Auto-generated method stub
		return username;
	}

	@Override
	public String getPassword() {
		// TODO Auto-generated method stub
		return password;
	}

	@Override
	public boolean isAccountNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		// TODO Auto-generated method stub
		return true;
	}

	@Override
	public boolean isEnabled() {
		// TODO Auto-generated method stub
		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);

	}

}

SecurityConfig.java (클래스 안에 autowired 추가, configure 내용 수정)

package edu.global.ex.config;

import org.springframework.beans.factory.annotation.Autowired;
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 edu.global.ex.security.CustomUserDetailsService;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private CustomUserDetailsService customUserDetailsService;

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.csrf().disable();

		http.authorizeRequests().antMatchers("/user/**").hasAnyRole("USER").antMatchers("/admin/**").hasAnyRole("ADMIN")
				.antMatchers("/**").permitAll();

		http.formLogin();
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
	}

}

3-3. 패스워드 암호화하기

  • localhost:8282/user/userHome > user, user 접속하면
    'Bad credentials' 출력하면서 에러 표시 (튕김)
2023-04-18 12:36:42.812  WARN 10172 --- [nio-8282-exec-5] e.g.e.security.CustomUserDetailsService  : Load User By UserVO number: user
2023-04-18 12:36:42.814  WARN 10172 --- [nio-8282-exec-5] e.g.e.security.CustomUserDetailsService  : queried by UserVO mapper: UserVO(username=user, password=user, enabled=1, authList=[AuthVO(username=user, authority=ROLE_USER)])
2023-04-18 12:36:42.815  WARN 10172 --- [nio-8282-exec-5] o.s.s.c.bcrypt.BCryptPasswordEncoder     : Encoded password does not look like BCrypt
  • BCyptPasswordEncoder는 암호화되어서 바뀐다.

UserMapper.java

  • src/test/java에 UserMapperTest 가 생성되었다.

  • testInsertUser 부분을 오른쪽 버튼 누르고 Run As - JUnit Test

  • Developer에서 새로운 계정을 확인한다.

  • localhost:8282/user/userHome 접속하고 kim2, kim2 접속

2023-04-18 12:53:57.828  WARN 3184 --- [nio-8282-exec-9] e.g.e.security.CustomUserDetailsService  : Load User By UserVO number: kim2
2023-04-18 12:53:57.832  WARN 3184 --- [nio-8282-exec-9] e.g.e.security.CustomUserDetailsService  : queried by UserVO mapper: UserVO(username=kim2, password=$2a$10$.OvP8tpGwQPZQNHr63aMyu8eXGE7pM0qqUZfNrNNlKJsdm0DqZZTe, enabled=1, authList=[AuthVO(username=kim2, authority=ROLE_USER)])
2023-04-18 12:53:57.955  INFO 3184 --- [io-8282-exec-10] edu.global.ex.controller.HomeController  : userHome ...
  • UserMapperTest에서 kim3,1234 / kim4,1234 도 각각 JUnitTest 넣어준다.
profile
velog, GitHub, Notion 등에 작업물을 정리하고 있습니다.

0개의 댓글