Spring Security 로그인 - eunja511005/Tutorial GitHub Wiki

1. 필요한 의존성 추가

- POM.xml 파일에 아래 내용 추가 

	    <!-- security 사용 위해 종속성 포함 -->
	        <dependency>
	                <groupId>org.springframework.boot</groupId>
	                <artifactId>spring-boot-starter-security</artifactId>
	        </dependency>
	    		
	    <!-- security test 사용 위해 종속성 포함 -->		
		<dependency>
			<groupId>org.springframework.security</groupId>
			<artifactId>spring-security-test</artifactId>
			<scope>test</scope>
		</dependency>	

2. 유저 테이블 생성

- schema.xml 파일에 아래 내용 추가


drop table zthm_user;
CREATE TABLE zthm_user
(
    username      VARCHAR2(30) NOT NULL,
    password      VARCHAR2(100),
    email         VARCHAR2(30),
    role          VARCHAR2(30),
    picture       VARCHAR2(50),
    enable        CHAR(1), 
    create_id     VARCHAR2(30),
    create_time   VARCHAR2(14),
    update_id     VARCHAR2(30),
    update_time   VARCHAR2(14)
);
COMMENT ON TABLE zthm_user IS '유저정보';
COMMENT ON COLUMN zthm_user.username IS '유저이름';
COMMENT ON COLUMN zthm_user.password IS '패스워드';
COMMENT ON COLUMN zthm_user.email IS '이메일';
COMMENT ON COLUMN zthm_user.role IS '역할';
COMMENT ON COLUMN zthm_user.picture IS '사진';
COMMENT ON COLUMN zthm_user.enable IS '사용여부';
COMMENT ON COLUMN zthm_user.create_id IS '생성자';
COMMENT ON COLUMN zthm_user.create_time IS '생성시간';
COMMENT ON COLUMN zthm_user.update_id IS '수정장';
COMMENT ON COLUMN zthm_user.update_time IS '수정시간';

3. 유저 테이블에 테스트 유저 입력

- data.xml 파일에 아래 내용 추가

insert into zthm_user(username, password, email, role, picture, enable, create_id, create_time, update_id, update_time) values('#####.park', '$2a$10$RWq20vPGyVlHLMxPCuyd6e9NFcqpCijj2MeWOMt/AcE4UcdN2qLZq', '#####[email protected]', 'sysadmin', '', '1', '#####.park', to_char(sysdate,'yyyymmddhh24mmss'), '#####.park', to_char(sysdate,'yyyymmddhh24mmss'));

4. 오라클 DB 서버 연결 정보, Mybatis 설정 정보 입력

- application.properties 파일에 아래 내용 추가

# database
spring.datasource.url=jdbc:oracle:thin:@IFreedomDB20230331_medium?TNS_ADMIN=D:/Users/#####/Downloads/Wallet_IFreedomDB20230331
spring.datasource.username=wasadmin
spring.datasource.password=************
 
# mybatis
mybatis.config=mybatis/mybatis-config.xml
mybatis.mapper-locations=mybatis/mapper/*.xml

5. 유정 정보 조회를 위한 DTO 생성

package com.eun.tutorial.dto;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import java.io.Serializable;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class UserInfoDTO implements Serializable {

    private static final long serialVersionUID = 658724990821020276L;

    private Long id;
    private String username;
    private String password;
    private String email;
    private String role;
    private String picture;
    private boolean isEnable;
    private String createId;
    private String createTime;
    private String updateId;
    private String updateTime;

    public UserInfoDTO update(String name, String picture){
        this.username = name;
        this.picture = picture;
        return this;
    }

}


6. 유저 정보 조회를 위한 mapper.xml 파일

- TestMapper.xml 파일에 아래 내용 추가

  <select id="getUser" parameterType="hashMap" resultType="com.eun.tutorial.dto.UserInfoDTO">
  	SELECT username, password, email, role, picture, enable,
  	       create_id, create_time, update_id, update_time
  	FROM zthm_user 
  	WHERE username = #{username}
  </select>

7. 유저 정보 조회를 위한 TestMapper 인터페이스 추가

- TestMapper 파일에 아래 내용 추가

@Mapper
public interface TestMapper {
    List<Book> getBookLists();
    UserInfoDTO getUser(Map<String, Object> map);
}

8. UserDetails 구현 클래스 생성

package com.eun.tutorial.service.user;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.eun.tutorial.dto.UserInfoDTO;

import java.util.Collection;
import java.util.HashSet;
import java.util.Objects;
import java.util.Set;

public class UserDetailsImpl implements UserDetails {

    private UserInfoDTO userInfoDTO;

    public UserDetailsImpl(UserInfoDTO user) {
        this.userInfoDTO = user;
    }

    @Override
    public boolean equals(Object o){
        if(this==o) return true;
        if(!(o instanceof UserDetailsImpl)) return false;
        UserDetailsImpl userDetails = (UserDetailsImpl) o;
        return userInfoDTO.getUsername().equals(userDetails.getUsername()) &&
               userInfoDTO.getPassword().equals(userDetails.getPassword());
    }

    @Override
    public int hashCode(){
        return Objects.hash(userInfoDTO.getUsername(), userInfoDTO.getPassword());
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Set<GrantedAuthority> roles = new HashSet<>();
        for (String role : userInfoDTO.getRole().split(",")){
            roles.add(new SimpleGrantedAuthority(role));
        }
        return roles;
    }

    @Override
    public String getPassword() {
        return userInfoDTO.getPassword();
    }

    @Override
    public String getUsername() {
        return userInfoDTO.getUsername();
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return userInfoDTO.isEnable();
    }
}

9. UserDetailsService 구현 클래스 생성

package com.eun.tutorial.service.user;

import java.util.HashMap;
import java.util.Map;

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 com.eun.tutorial.dto.UserInfoDTO;
import com.eun.tutorial.mapper.TestMapper;

import lombok.RequiredArgsConstructor;

@RequiredArgsConstructor
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    private final TestMapper testDao;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		Map<String, Object> map = new HashMap();
		map.put("username", username); // 가져온 데이터에 키와 벨류값을 지정
        UserInfoDTO optionalUser = testDao.getUser(map);
        
        if(optionalUser != null) {
        	return new UserDetailsImpl(optionalUser);
        }else{
        	return null;
        }
    }
}

10. spring security에서 인증을 위한 설정 내용 추가

- MyWebSecurityConfigurerAdapter 파일에 아래 내용 추가 

        /**
         * 5.로그인 설정
         *   1) 로그인 페이지 설정
         *   2) 로그인 페이지에서 로그인을 위해 호출 하는 url 설정
         *   3) 나머지는 인증 후 접속 가능토록 설정
         *   4) 로그인 성공시 핸들러 설정
         *   5) 로그인 실패시 핸들서 설정
         *   6) 모두 로그 아웃에 접근 가능
         */
        http
                .formLogin() // 로그인에 관한 설정
//                    .loginPage("/loginForm") // 로그인 페이지 링크
//                    .loginProcessingUrl("/signin")
//                	.usernameParameter("userId")
                    .successHandler((request, response, auth)->{
                        for (GrantedAuthority authority : auth.getAuthorities()){
                            log.info("Authority Information {} ", authority.getAuthority());
                        }
                        log.info("getName {} ",auth.getName());
                        Map<String, String> res = new HashMap<>();
                        response.sendRedirect("/");
                        
//                      Map<String, String> res = new HashMap<>();
//                        res.put("result", "login success");
//                        JSONObject json =  new JSONObject(res);
//                        response.setContentType("application/json; charset=utf-8");
//                        response.getWriter().print(json);
                    })
                    .failureHandler((request, response, exception)->{
                        String errMsg = "";
                        if(exception.getClass().isAssignableFrom(BadCredentialsException.class)){
                            errMsg = "Invalid username or password";
                            //response.setStatus(401);
                        }else{
                            errMsg = "UnKnown error - "+exception.getMessage();
                            //response.setStatus(400);
                        }
//                        zthmErrorRepository.save(ZthmError.builder()
//                                .errorMessage("Login Error : "+exception.getMessage())
//                                .build());
//                        Map<String, String> res = new HashMap<>();
//                        res.put("result", errMsg);
//                        JSONObject json =  new JSONObject(res);
//                        response.setContentType("application/json; charset=utf-8");
//                        response.getWriter().print(json);
                        response.sendRedirect("/login");
                    })
                    .permitAll(); 

11. spring security에서 인증을 위한 bean 추가

- MyWebSecurityConfigurerAdapter 파일에 아래 내용 추가 

    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

12. 구현 내용

- http://localhost:8080 입력시 로그인 화면으로 이동 됨
- 테스트 입력한 맞는 인증 정보 입력 시 메인 페이지로 이동('/')
- 잘못된 인증 정보 입력시 로그 화면으로 다시 이동('/login')

image

13. git main 브랜치에 반영

- 로컬에서 서버로 푸쉬
cd D:\Users\ywbes\git\Tutorial
git status
git add src/test/java/com/eun/tutorial/TutorialApplicationTests.java
git status
git commit -m ":new: spring security 활용 로그인 기능 추가"
git push

- 서버에 commit 확인
https://github.com/eunja511005/Tutorial

image

image

⚠️ **GitHub.com Fallback** ⚠️