스프링 시큐리티

Stormi·2022년 8월 17일
0

개발

목록 보기
14/20

SecurityConfig


package com.example.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
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;

@Configuration
@EnableWebSecurity //스프링 시큐리티 필터가 스프링 필터체인에 등록이 됨.
@EnableGlobalMethodSecurity(securedEnabled = true) //secured 어노테이션 활성
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    //@Bean을 적으면 해당 메서드의 리턴되는 오브젝트를 IoC로 등록해준다.
    @Bean
    public BCryptPasswordEncoder encodePwd() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable(); // 비활성화
        http.authorizeRequests()
                .antMatchers("/user/**").authenticated() //인증만되면 들어갈 수 있는 주소
                .antMatchers("/manager/**").access("hasRole('ROLE_ADMIN') or hasRole('ROLE_MANAGER')")
                .antMatchers("/admin/**").access("hasRole('ROLE_ADMIN')")
                .anyRequest().permitAll() //다른 요청들은 전부 permitAll
                .and()
                .formLogin()
                .loginPage("/loginForm")
                .loginProcessingUrl("/login") //이렇게 해두면 "/login" 주소가 호출이 되면 시큐리티가 낚아채서 대신 로그인을 진행시켜준다. -> 그러면
        // 컨트롤러에 /login을 만들지 않아도된다. 시큐리티가 대신 로그인을 진행시켜주기 때문에
                .defaultSuccessUrl("/"); // main 페이지로 가게하기





        // /user로하면 403 에러가 뜨는 데 이것은 접근 권한이 없다는 뜻이다.
        //로그인을 안했기 때문에, manager, admin도 마찬가지이다.
        // 다른것들은 잘가짐, permitAll했기 때문이다.
        //스프링 시큐리티가 낚아 채지 않음, 비활성화됨


    }
}

컨트롤러

@PostMapping("/join")
    public String join(User user) {
        user.setRole("ROLE_USER");
//        userRepository.save(user); // 회원가입이 잘 됨, 비밀번호가 1234 -> 이렇게 되면 시큐리티로 로그인을 할 수 없음
        // -> 이유는 패스워드가 암호화가 안되었기 떄문이다.
        // 따라서 패스워드 암호화를 해야함 -> securityConfig에서
        String rawPassword = user.getPassword();
        String encPassword = bCryptPasswordEncoder.encode(rawPassword);
        user.setPassword(encPassword);
        userRepository.save(user);
        return "redirect:/loginForm";
    }

    //SecurityConfig에 있는
    //@EnableGlobalMethodSecurity(securedEnabled = true) //secured 어노테이션 활성
    // 이부분에 의해 특정메소드에 간단하게 이렇게 걸고 싶을 때 사용
    @Secured("ROLE_ADMIN")
    @GetMapping("/info")
    public @ResponseBody String info() {
        return "개인정보";
    }

PrincipalDetails

package com.example.security.config.auth;


//시큐리티가 /login 주소 요청이 오면 낚아채서 로그인을 진행시킨다.
// 로그인을 진행이 완료가 되면 시큐리티 session 을 만들어준다. (Security ContextHolder)라는 이 키값에 세션 정보를 저장한다.
// 이때 session에 들어갈 수 있는 정보는 즉,  시큐리티가 가지고 있는 session에 들어갈 수 있는 오브젝트가 있는데
// 오브젝트 타입 => Authentication 타입 객체이다.
// Authentication 안에 User정보가 있어야함.
// 이것도 클래스가 정해져 있음
// User오브젝트의 타입은 => UserDetails 타입객체

// 시큐리티가 가지고 있는 session 영역이 있다.
// 즉, 시큐리티 세션 영역에 세션 정보를 저장해주는데, 여기 들어갈 수 있는 객체 정해져있음 -> Authentication으로
// 이, Authentication에 User 정보를 저장할 때, User 정보는 UserDetails 타입이어야함

import com.example.security.model.User;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

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

public class PrincipalDetails implements UserDetails {

    private User user; //콤포지션

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

    //해당 User의 권한을 리턴하는 곳!!
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
//        user.getRole(); -> string 타입이라 리턴이 불가능
        Collection<GrantedAuthority> collect = new ArrayList<>();
        collect.add(new GrantedAuthority() {
            @Override
            public String getAuthority() {
                return user.getRole();
            }
        });
        return collect;
    }

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

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

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

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

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

    @Override
    public boolean isEnabled() {
        // 우리 사이트에서 1년동안 회원이 로그인을 안하면 휴면계정으로 하기로했다면
        // User.getLoginDate()를 가져와서 저 날짜로부터 현재시간 - 저 날짜시간 해서 일년을 초과하면
        // return 을 false로 하면됨
        return true;
    }
}

Security Session => Authentication => UserDetails(PrincipalDetails)

PrincipalDetailsService

package com.example.security.config.auth;

import com.example.security.model.User;
import com.example.security.repository.UserRepository;
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;

// 이때 만족을함
// 시큐리티 설정에서 loginProcessingUrl("/login) 으로 걸어놨기 때문에
// /login 요청이 오면 자동으로 UserDetailsService 타입으로 IoC 되어 있는
//loadUserByUsername 함수가 실행이됨
@Service
public class PrincipalDetailsService implements UserDetailsService {

    @Autowired
    private UserRepository userRepository;

    //시큐리티 session => Authentication = > UserDetails
    // 이게 리턴이 되면
    //Authentication(UserDetails) 이렇게 Authentication 내부에 쏘옥 들어감
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User userEntity = userRepository.findByUsername(username);
        if (userEntity != null) {
            return new PrincipalDetails(userEntity);
        }
        return null;
    }
}

loginForm.html

저기 있는 username을 받는 곳이 PrincipalDetailsService의 loadUserByUsername(String username) 함수의 파라미터

만약 loginForm.html에 username2로 받는다면 저기 안들어감!!!

인프런강의 시큐리티 무료강의를 수강했습니다.

0개의 댓글