Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
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
Tags
more
Archives
Today
Total
관리 메뉴

블로그 이름 뭐하지

[Spring] Spring Security 본문

Spring

[Spring] Spring Security

가는말이고우면오는말은come 2024. 11. 14. 17:30

Spring 서버에 필요한 인증, 인가를 위해 많은 기능을 제공하는 프레임 워크로,

여러 개의 Filter를 체인 형식으로 사용해 요청을 처리한다.

해당 필터들은 스프링이 기본제공하는 DelegatingFilterProxy 스프링 필터에서 시작해

Security Filter Chain을 따라 순차적으로 작동한다.

Security의 필터는 스프링 필터이므로 기본적으로 개발자의 커스텀 필터보다 앞에서 적용되며,

필터의 위치를 바꾸고 싶은 경우 allFilterBefore(), allFilterAfter() 같은 설정으로 위치를 이동시킬 수 있다.

 

Spring Security 주요 모듈

 

  • Authentication : 접근하는 주체의 정보와 권한을 담는 인터페이스
    + principal : 사용자를 식별한다(UserDetails 인스턴스)
    + credentials : 주로 비밀번호, 대부분 사용자 인증에 사용한 후 비운다
    + authorites : 사용자에게 부여한 권한을 GrantedAuthority로 추상화하여 사용한다.
  • SecurityContext : Authentication을 보관하는 역할로, 이를 통해 Authentication 객체를 꺼내올 수 있다.
  • SecurityContextHolder : 보안 주체의 세부정보를 포함한 현재 보안 컨텍스트의 세부정보가 저장된다.

유저가 로그인을 성공하면, principal과 credential 정보를 Authentication에 담고,

Spring Security가 Authentication을 SecurityContext에 보관한다.

그리고 SecurityContext를 SecurityContextHolder에 담아 보관한다.

 

  • UserDetails : 로그인(인증)에 성공하여 생성된 UserDetails 객체는 Authentication 객체를 구현한 UserPasswordAuthenticationToken을 생성하기 위해 사용된다.(Custom하여 Bean으로 등록 후 사용한다)
  • UserDetailsService : UserDetails 객체를 반환하는 하나의 메서드만을 가지고, 이를 구현한 클래스에 UserRepository를 주입받아 DB와 연결하여 처리한다.(DB의 사용자 정보 조회) (Custom하여 Bean으로 등록 후 사용한다)
  • UserPasswordAuthenticationToken : Authentication을 구현한 AbstractAuthenticationToken의 하위클래스로, User의 ID가 principal, Password가 credential 역할을 한다.
  • AuthenticationManager : 인증에 대한 부분을 처리한다. 실질적으로는 AuthenticationManager에 등록된 AuthenticationProvider에 의해 처리된다. 인증에 성공하면 객체를 생성해 SecurityFContext에 저장한다.
  • AuthenticationProvider : 실제 인증에 대한 부분을 처리하고, 인증 전의 Authentication 객체를 받아 인증이 완료된 객체를 반환한다.

 

Spring Security 인증 처리 과정

1) 클라이언트에서 로그인 시도

2) AuthenticationFilter에서 인증 처리 : 이 중 UsernamePasswordAuthenticationFilter에서 인증을 처리한다. AuthenticationFilter는 HttpSevletRequest에서 아이디와 비밀번호를 추출해 UsernameAuthenticationToken을 발급한다.

3) AuthenticationFilter는 AuthenticationManager에게 인증 객체를 전달한다. AuthenticationManger는 인증을 담당하여 발급된 토큰이 올바른 유저인지 확인한다.

4) AuthenticationManager가 AuthenticationProvider에게 인증객체를 전달한다.

5) 전달받은 객체의 정보는 UserDetailService에 넘겨진다.

6) UserDetailService는 전달받은 정보를 통해 DB에서 사용자를 찾고 그를 기반으로한 UserDetails를 구현한 객체를 반환한다.

7) UserDetail 객체를 AuthenticationProvider에 전달한다.

8) AuthenticationProvider는 전달받은 UserDetails를 인증해 성공하면 ProvideManager에게 권한을 담은 검증된 인증객체를 전달한다.

9) 검증된 인증객체는 AuthenticationFilter에 전달된다.

10) 검증된 인증 객체(UserDetails)를 SecurityContextHolder안의 SecurityContext에 저장한다.

인증 처리된 사용자 정보 가져오기

1) Bean에서 가져오기

전역에 선언된 SecurityContexHolder에서 가져온다.

2) Controller에서 가져오기

principal 객체 뿐 아니라 Authentication 토큰도 가져올 수 있다.

3) @AuthenticationPrincipal 사용

SpringSecurity 3.2 부터 등장하는 기능으로 어노테이션을 이용해 사용자 객체를 인자에 주입한다.

 

Security 사용

사용할 때는 build.gradle에 아래와 같은 설정을 추가한다.

// Security
implementation 'org.springframework.boot:spring-boot-starter-security'

 

로그인 구현

Spring Security 기능을 이용하기 위해서 WebSecurityConfig를 생성한다.

package com.sparta.springauth.config;

import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.Customizer;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
@EnableWebSecurity // Spring Security 지원을 가능하게 함
public class WebSecurityConfig {

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF(사이트 간 요청 위조)
        // 공격자가 쿠키의 세션 정보를 탈취해 웹서비스에 사용자가 의도하지 않은 요청을 전달한다
        // CSRF 설정이 되어있을 경우 Html에서 CSRF 토큰 값을 넘겨주어야 요청 수신이 가능하다
        // Rest방식의 API에서는 disable이 가능하다
        http.csrf((csrf) -> csrf.disable());

        http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        // resources 접근 허용 설정
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        // '/api/user/'로 시작하는 요청 모두 접근 허가
                        // 회원 비회원 상관없이 모두 접근이 가능하도록 함
                        .requestMatchers("/api/user/**").permitAll()
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

        // 로그인 사용
        http.formLogin((formLogin) ->
                formLogin
                        // 로그인 View 제공 (GET /api/user/login-page)
                        .loginPage("/api/user/login-page")
                        // 로그인 처리 API (POST /api/user/login)
                        .loginProcessingUrl("/api/user/login")
                        // 로그인 처리 후 성공 시 URL
                        .defaultSuccessUrl("/")
                        // 로그인 처리 후 실패 시 URL
                        .failureUrl("/api/user/login-page?error")
                        .permitAll()
        );

        return http.build();
    }
}

 

DB의 회원정보 조회를 Spring Security의 인증 관리자에게 전달하기 위해

UserDetails와 UserDetailsService를 직접 구현한다.

이렇게 직접 구현하면 Security의 Default 로그인 기능을 사용하지 않아,

Security의 Password를 더이상 제공하지 않는다.

 

로그인 요청이 들어오면 UserDetailsService를 통해 인증 확인 작업이 이뤄지고,

인증 객체에 직접 구현한 UserDetails가 담기게 된다.

package com.sparta.springauth.security;

import com.sparta.springauth.entity.User;
import com.sparta.springauth.repository.UserRepository;
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;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    private final UserRepository userRepository;

    public UserDetailsServiceImpl(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
		
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userRepository.findByUsername(username)
                .orElseThrow(() -> new UsernameNotFoundException("Not Found " + username));

        return new UserDetailsImpl(user);
    }
}
package com.sparta.springauth.security;

import com.sparta.springauth.entity.User;
import com.sparta.springauth.entity.UserRoleEnum;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;

public class UserDetailsImpl implements UserDetails {

    private final User user;

    public UserDetailsImpl(User user) {
        this.user = user;
    }

    public User getUser() {
        return user;
    }

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

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

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        UserRoleEnum role = user.getRole();
        String authority = role.getAuthority();

        SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(authority);
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        authorities.add(simpleGrantedAuthority);

        return authorities;
    }

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

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

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

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

 

@AuthenticationPrincial을 통해 Authentication의 Principal에 저장된 UserDetailsImpl를 가져와서,

UserDetailsImpl에 저장된 인증된 사용자 User 객체를 사용할 수 있다.

@Controller
@RequestMapping("/api")
public class ProductController {

    @GetMapping("/products")
    public String getProducts(@AuthenticationPrincipal UserDetailsImpl userDetails) {
        // Authentication 의 Principal 에 저장된 UserDetailsImpl 을 가져옵니다.
        User user =  userDetails.getUser();
        System.out.println("user.getUsername() = " + user.getUsername());

       return "redirect:/";
    }
}

 

JWT 로그인 구현

 

JWT 토큰을 이용해서 로그인을 구현하기 위해서는 JWT 토큰을 처리할 Filter가 필요하다

 

1) JwtAuthenticationFilter : 로그인 진행과 JWT 생성

package com.sparta.springauth.jwt;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sparta.springauth.dto.LoginRequestDto;
import com.sparta.springauth.entity.UserRoleEnum;
import com.sparta.springauth.security.UserDetailsImpl;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import java.io.IOException;

@Slf4j(topic = "로그인 및 JWT 생성")
public class JwtAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
    private final JwtUtil jwtUtil;

    public JwtAuthenticationFilter(JwtUtil jwtUtil) {
        this.jwtUtil = jwtUtil;
        setFilterProcessesUrl("/api/user/login");
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        log.info("로그인 시도");
        try {
            LoginRequestDto requestDto = new ObjectMapper().readValue(request.getInputStream(), LoginRequestDto.class);

            return getAuthenticationManager().authenticate(
                    new UsernamePasswordAuthenticationToken(
                            requestDto.getUsername(),
                            requestDto.getPassword(),
                            null
                    )
            );
        } catch (IOException e) {
            log.error(e.getMessage());
            throw new RuntimeException(e.getMessage());
        }
    }

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        log.info("로그인 성공 및 JWT 생성");
        String username = ((UserDetailsImpl) authResult.getPrincipal()).getUsername();
        UserRoleEnum role = ((UserDetailsImpl) authResult.getPrincipal()).getUser().getRole();

        String token = jwtUtil.createToken(username, role);
        jwtUtil.addJwtToCookie(token, response);
    }

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        log.info("로그인 실패");
        response.setStatus(401);
    }
}

 

2) JwtAuthorization : API에 전달되는 JWT 유효성 검증 및 인가 처리

package com.sparta.springauth.jwt;

import com.sparta.springauth.security.UserDetailsServiceImpl;
import io.jsonwebtoken.Claims;
import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import java.io.IOException;

@Slf4j(topic = "JWT 검증 및 인가")
public class JwtAuthorizationFilter extends OncePerRequestFilter {

    private final JwtUtil jwtUtil;
    private final UserDetailsServiceImpl userDetailsService;

    public JwtAuthorizationFilter(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService) {
        this.jwtUtil = jwtUtil;
        this.userDetailsService = userDetailsService;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain filterChain) throws ServletException, IOException {

        String tokenValue = jwtUtil.getTokenFromRequest(req);

        if (StringUtils.hasText(tokenValue)) {
            // JWT 토큰 substring
            tokenValue = jwtUtil.substringToken(tokenValue);
            log.info(tokenValue);

            if (!jwtUtil.validateToken(tokenValue)) {
                log.error("Token Error");
                return;
            }

            Claims info = jwtUtil.getUserInfoFromToken(tokenValue);

            try {
                 setAuthentication(info.getSubject());
            } catch (Exception e) {
                log.error(e.getMessage());
                return;
            }
        }

        filterChain.doFilter(req, res);
    }

    // 인증 처리
    public void setAuthentication(String username) {
        SecurityContext context = SecurityContextHolder.createEmptyContext();
        Authentication authentication = createAuthentication(username);
        context.setAuthentication(authentication);

        SecurityContextHolder.setContext(context);
    }

    // 인증 객체 생성
    private Authentication createAuthentication(String username) {
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);
        return new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
    }
}

 

3) WebSecurityConfig에 필터 등록

package com.sparta.springauth.config;

import com.sparta.springauth.jwt.JwtAuthorizationFilter;
import com.sparta.springauth.jwt.JwtAuthenticationFilter;
import com.sparta.springauth.jwt.JwtUtil;
import com.sparta.springauth.security.UserDetailsServiceImpl;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity // Spring Security 지원을 가능하게 함
public class WebSecurityConfig {

    private final JwtUtil jwtUtil;
    private final UserDetailsServiceImpl userDetailsService;
    private final AuthenticationConfiguration authenticationConfiguration;

    public WebSecurityConfig(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService, AuthenticationConfiguration authenticationConfiguration) {
        this.jwtUtil = jwtUtil;
        this.userDetailsService = userDetailsService;
        this.authenticationConfiguration = authenticationConfiguration;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        JwtAuthenticationFilter filter = new JwtAuthenticationFilter(jwtUtil);
        filter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
        return filter;
    }

    @Bean
    public JwtAuthorizationFilter jwtAuthorizationFilter() {
        return new JwtAuthorizationFilter(jwtUtil, userDetailsService);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf((csrf) -> csrf.disable());

        // 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
        http.sessionManagement((sessionManagement) ->
                sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        );

        http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                        .requestMatchers("/api/user/**").permitAll() // '/api/user/'로 시작하는 요청 모두 접근 허가
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

        http.formLogin((formLogin) ->
                formLogin
                        .loginPage("/api/user/login-page").permitAll()
        );

        // 필터 관리
        http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        return http.build();
    }
}

 

접근불가 페이지 구현

일반 사용자와 관리자를 구별하는 페이지로 인가처리가 필요하다.

 

1) Spring Security에 권한(Authority) 설정 방법

회원 상세정보(UserDetailsImpl)를 통해 1개 이상의 권한 설정이 가능하다.

권한 이름은 "ROLE_"로 시작해야 한다. (ROLE_ADMIN, ROLE_USER)

public enum UserRoleEnum {
    USER(Authority.USER),  // 사용자 권한
    ADMIN(Authority.ADMIN);  // 관리자 권한

    private final String authority;

    UserRoleEnum(String authority) {
        this.authority = authority;
    }

    public String getAuthority() {
        return this.authority;
    }

    public static class Authority {
        public static final String USER = "ROLE_USER";
        public static final String ADMIN = "ROLE_ADMIN";
    }
}

 

2) Spring Security를 이용한 API 별 권한 제어 방법

Controller에 @Secured 어노테이션으로 권한 설정을 부여한다.

@Secured(UserRoleEnum.Authority.ADMIN) // 관리자용
@GetMapping("/products/secured")
public String getProductsByAdmin(@AuthenticationPrincipal UserDetailsImpl userDetails) {
    System.out.println("userDetails.getUsername() = " + userDetails.getUsername());
    for (GrantedAuthority authority : userDetails.getAuthorities()) {
        System.out.println("authority.getAuthority() = " + authority.getAuthority());
    }  
    
    return "redirect:/";
}

 

 

WebSecurityConfig에서 @Secured 어노테이션을 활성화 하고,

접근 불가 페이지 설정을 추가한다 (forbidden.html 파일 추가 필요)

package com.sparta.springauth.config;

import com.sparta.springauth.jwt.JwtAuthorizationFilter;
import com.sparta.springauth.jwt.JwtAuthenticationFilter;
import com.sparta.springauth.jwt.JwtUtil;
import com.sparta.springauth.security.UserDetailsServiceImpl;
import org.springframework.boot.autoconfigure.security.servlet.PathRequest;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Configuration
@EnableWebSecurity // Spring Security 지원을 가능하게 함
@EnableMethodSecurity(securedEnabled = true) // ★@Secured 애너테이션을 활성화 한다.
public class WebSecurityConfig {

    private final JwtUtil jwtUtil;
    private final UserDetailsServiceImpl userDetailsService;
    private final AuthenticationConfiguration authenticationConfiguration;

    public WebSecurityConfig(JwtUtil jwtUtil, UserDetailsServiceImpl userDetailsService, AuthenticationConfiguration authenticationConfiguration) {
        this.jwtUtil = jwtUtil;
        this.userDetailsService = userDetailsService;
        this.authenticationConfiguration = authenticationConfiguration;
    }

    @Bean
    public AuthenticationManager authenticationManager(AuthenticationConfiguration configuration) throws Exception {
        return configuration.getAuthenticationManager();
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() throws Exception {
        JwtAuthenticationFilter filter = new JwtAuthenticationFilter(jwtUtil);
        filter.setAuthenticationManager(authenticationManager(authenticationConfiguration));
        return filter;
    }

    @Bean
    public JwtAuthorizationFilter jwtAuthorizationFilter() {
        return new JwtAuthorizationFilter(jwtUtil, userDetailsService);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        // CSRF 설정
        http.csrf((csrf) -> csrf.disable());

        // 기본 설정인 Session 방식은 사용하지 않고 JWT 방식을 사용하기 위한 설정
        http.sessionManagement((sessionManagement) ->
                sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        );

        http.authorizeHttpRequests((authorizeHttpRequests) ->
                authorizeHttpRequests
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll() // resources 접근 허용 설정
                        .requestMatchers("/api/user/**").permitAll() // '/api/user/'로 시작하는 요청 모두 접근 허가
                        .anyRequest().authenticated() // 그 외 모든 요청 인증처리
        );

        http.formLogin((formLogin) ->
                formLogin
                        .loginPage("/api/user/login-page").permitAll()
        );

        // 필터 관리
        http.addFilterBefore(jwtAuthorizationFilter(), JwtAuthenticationFilter.class);
        http.addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);

        // ★접근 불가 페이지
        http.exceptionHandling((exceptionHandling) ->
                exceptionHandling
                        // "접근 불가" 페이지 URL 설정
                        .accessDeniedPage("/forbidden.html")
        );

        return http.build();
    }
}

참고한 링크

 

Spring Security란? 사용하는 이유부터 설정 방법까지 알려드립니다! I 이랜서 블로그

홈페이지에 인증 및 권한 기능을 빠르게 부여해 인증 및 권한 보호 기능을 손쉽게 추가할 수 있는 Spring의 프레임워크 중 하나인 ‘Spring Security’에 대해 이랜서에서 자세히 알려드립니다. I spring

www.elancer.co.kr

 

 

[Spring] Spring Security 개념과 처리 과정 👮‍♀️ (+근데 상황극을 곁들인)

오늘도 노드 마을에서 온.. 토끼는 낯선 기술에 울고 있다..(?) 그렇다.. 유저가 있는 서비스라면 인증과 인가 처리는 필수이다. Spring에서는 Spring Security라는 프레임워크로 관련 기능을 제공하고

hello-judy-world.tistory.com

 

'Spring' 카테고리의 다른 글

[Spring] RestTemplate과 OpenAPI  (0) 2024.11.15
[Spring] Validation  (0) 2024.11.14
[Spring] 필터(Filter)  (0) 2024.11.14
[Spring] 쿠키와 세션, JWT  (0) 2024.11.13
[Spring] Bean  (0) 2024.11.13