본문 바로가기

프로그래밍/Security

Security_Spring Security

반응형

Spring Security

: 스프링 시큐리티는 스프링 기반의 애플리케이션의 보안을 담당하는 스프링 하위 프레임워크이다. 

주로 필터에서 돌아간다.

 

즉, Security는 보안 체계를 강화하기 위해 사용한다.

 

 

보안 용어

  • 인증 (Authentication)
    : 보호된 리소스에 접근 대상에 대해 이 유저가 누구인지, 애플리케이션의 작업을 수행해도 되는 주체인지 확인하는 과정
  • 인가 (Authorize)
    : 해당 리소스에 대해 접근 가능한 권한을 가지고 있는지 확인하는 과정 

 

 

Security를 사용하기 위해서 build.gradle에서 의존성 추가하기

// security
// https://mvnrepository.com/artifact/org.springframework.security/spring-security-taglibs
implementation 'org.springframework.security:spring-security-taglibs:5.6.2'

 

https://www.baeldung.com/spring-security-taglibs

 

→ 사용 태그 라이브러리 선언

<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %>

 

→ ‘인증된 사용자라면‘ 이라는 뜻

<sec:authorize access="isAuthenticated()">
    Welcome Back, <sec:authentication property="name"/>
</sec:authorize>

 

 

&rarr; 인증 로직 만들기 &rarr;&nbsp; id, pw 체크 &rarr;&nbsp; 성공, 실패 로직 따로 구현하기

 

 

시큐리티 주소 설계 권한 부여 페이지 앞에는 /auth 붙일 예정

auth 패키지 

  • UserDetails
    : Spring Security에서 사용자의 정보를 담는 인터페이스
  • UserDetailService
    : Spring Security에서 유저의 정보를 가져오는 인터페이스

auth/PrincipalDetail.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public class PrincipalDetail implements UserDetails {
    
    // User
    private User user;
    
    public PrincipalDetail(User user) {
        this.user = user;
    }
    
    // 계정의 권한을 반환한다.
    @Override
    public Collection<extends GrantedAuthority> getAuthorities() {
        // "ROLE_" 스프링 시큐리티 규칙 (꼭 넣어야 함!)
        // "ROLE_" + user.getRole();
        Collection<GrantedAuthority> collections = new ArrayList<GrantedAuthority>();
        
        collections.add(() -> {
            return "ROLE_" + user.getRole();
        });
        
        return collections;
    }
    
    @Override
    public String getPassword() {
        return user.getPassword();
    }
    
    @Override
    public String getUsername() {
        return user.getUsername();
    }
    
    // 계정 만료되지 않았는지 여부를 리턴 / true : 게정 만료 안 됨, false : 계정 만료 됨
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    
    // 계정 잠김 여부 확인 / true : 사용 가능, flase : 사용 불가능
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }
    
    // 비밀번호 만료 여부를 리턴 / true : 사용 가능, flase : 사용 불가능
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    
    // 계정 활성화 여부 / true : 사용 가능, false : 로그인 불가능
    @Override
    public boolean isEnabled() {
        return true;
    }
}
cs

 

 

auth/PrincipalDetailService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@Service 
public class PrincipalDetailService implements UserDetailsService {
 
    @Autowired
    private UesrRepository userRepository;
    
    @Override
    public UserDetails loadUserByUsername(String username) throw UsernameNotFoundException {
        // 유저 이름, 비밀번호 같이 받게 설계
        // !! 시큐리티는 비밀번호 확인하지 않음. -> DB 사용자 계정이 있는지만 먼저 검사한다. 
        User principal = userRepository.findByUsername(username).orElseThrow(() -> {
            return new UsernameNotFoundException("해당 유저를 찾을 수 없습니다.");
        });
        
        // 시큐리티 세션 영역에 유저 정보가 저장
        return new PrincipalDetail(principal);
        
    }
 
}
cs

 

 

Config패키지

  • WebSecurityConfigurerAdapter
    : 스프링 시큐리티의 웹 보안 기능의 초기화 및 설정을 담당한다.

SecurityConfig.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
/* 권한 부여 페이지 설정
   1. /auth/joinPage
   2. /auth/loginPage
   3. /auth/**
*/
 
@Configuration // IoC 등록
@EnableWebSecurity // Security 필터로 등록을 해라 (+ 필터 커스텀)
@EnableGlobalMethodSecurity(prePostEnabled = true// 특정 주소로 접근하면 권한 및 인증 처리를 미리 하겠다.
public class SecurityConfig extends WebSecurityConfigurerAdapter {
 
    @Autowired
    private PrincipalDetailService principalDetailService;
    
    @Bean 
    public BCryptPasswordEncoder encodedPwd() {
        return new BCryptPasswordEncoder();
    }
    
    // 특정 주소 필터를 설정할 예정
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        
        http.csrf().disable(); // csrf 토큰 비활성화 처리 (테스트시 사용 권장)
        
        http.authorizeHttpRequests()
        .antMatchers("/auth/**""/""/js/**""/css/**""/images/**")
        .permitAll()
        .anyRequest()
        .authenticated()
        .and().formLogin()
        .loginPage("/auth/loginPage"// 시큐리티 로그인 페이지를 우리가 만든 페이지로 커스텀 
        .loginProcessingUrl("/auth/loginProc")
        .defaultSuccessUrl("/");
    }
    
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(principalDetailService).passwordEncoder(encodePwd());
    }
    
}
cs

 

 

UserService.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@Service
public class UserService {
    
    @Autowired
    private UserRepository userRepository;
    @Autowired 
    private BCryptPasswordEncoder encoder;
    
    @Transactional
    public int createUser(User user) {
        try {
            String rawPwd = user.getPassword();
            String encPwd = encoder.encode(rawPwd);
            
            user.setRole("user");
            user.setPassword(encPwd);
            userRepository.save(user);
            
            return 1;
        } catch (Exception e) {
            e.printStackTrace();
        }
        
        return -1;
    }
 
}
cs

 

 

UserApiController.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RestController
public class UserApiController {
 
    @Autowired
    private UserService userService;
    
    @Autowired
    private HttpSession session;
    
    // 회원가입 처리
    @PostMapping("/api/user")
    public ResponseDto<Integer> saveUser(@RequestBody User user) {
        int result = userService.createUser(user);
        
        return new ResponseDto<>(HttpStatus.OK, result);
    }
 
}
cs

 

 

header.jsp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>그린스블로그</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/css/bootstrap.min.css">
<script src="https://cdn.jsdelivr.net/npm/jquery@3.6.4/dist/jquery.slim.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/popper.js@1.16.1/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.2/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
</head>
<body>
    <sec:authorize access="isAuthenticated()">
    Welcome Back, <sec:authentication property="name" />
    Welcome Back, <sec:authentication property="principal" var="principal"/>
    </sec:authorize>
    <nav class="navbar navbar-expand-md bg-dark navbar-dark">
        <a class="navbar-brand" href="/">Home</a>
 
        <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#collapsibleNavbar">
            <span class="navbar-toggler-icon"></span>
        </button>
 
        <div class="collapse navbar-collapse" id="collapsibleNavbar">
            <ul class="navbar-nav">
                <c:choose>
                    <%-- <c:when test="${principal != null}"> --%>
                    <c:when test="${empty principal}">
                        <li class="nav-item"><a class="nav-link" href="/auth/loginPage">로그인</a></li>
                        <li class="nav-item"><a class="nav-link" href="/auth/joinPage">회원가입</a></li>
                    </c:when>
                    <c:otherwise>
                        <li class="nav-item"><a class="nav-link" href="#">글쓰기</a></li>
                        <li class="nav-item"><a class="nav-link" href="#">회원정보</a></li>
                        <li class="nav-item"><a class="nav-link" href="/logout">로그아웃</a></li>
                    </c:otherwise>
                </c:choose>
            </ul>
        </div>
    </nav>
    <br>
cs
반응형

'프로그래밍 > Security' 카테고리의 다른 글

Security_시큐리티 동작 방식  (0) 2023.07.16