[Spring Security] basic-login 실습

WOOK JONG KIM·2022년 11월 29일
0

패캠_java&Spring

목록 보기
74/103
post-thumbnail

RequestInfo

@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder

public class RequestInfo {

    private String remoteIp;
    private String sessionId;
    private LocalDateTime loginTime;
}

CustomAuthDetail

@Component
public class CustomAuthDetails implements AuthenticationDetailsSource<HttpServletRequest, RequestInfo> {
    // 로그인이 일어날때 request에서 정보를 가져다가 넣어서 보내주는 것
    @Override
    public RequestInfo buildDetails(HttpServletRequest request) {
        return RequestInfo.builder()
                .remoteIp(request.getRemoteAddr())
                .sessionId(request.getSession().getId())
                .loginTime(LocalDateTime.now())
                .build();
    }
}

SecurityConfig

@EnableWebSecurity(debug = true)
// 유저로 로그인 시 관리자 페이지까지 접근 되는 것을 막기 위해 밑 어노테이션 지정
// 지정 시 Controller에 지정한 @PreAuthorize가 반영됨
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final CustomAuthDetails customAuthDetails;

    public SecurityConfig(CustomAuthDetails customAuthDetails) {
        this.customAuthDetails = customAuthDetails;
    }

    // 관리자가 User page 접근 시 에러가 안나고 접근할 수 있게 하는 코드
    @Bean
    RoleHierarchy roleHierarchy(){
        RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
        roleHierarchy.setHierarchy("ROLE_ADMIN > ROLE_USER");
        return roleHierarchy;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests(request->{
                    request
                            .antMatchers("/").permitAll()
                            // 메인 페이지 말고는 허락 받고 들어와
                            // 이것만 설정시 CSS가 내려 가지 않음
                            .anyRequest().authenticated();
                })
                .formLogin(
                        login -> login.loginPage("/login")
                                // 현재 위에서 (/), 즉 메인페이지말고는 로그인을 받고 들어갈 수 있음(로그인 페이지 또한 인증이 필요한것으로 설정)
                                .permitAll() // 따라서 permitAll() 붙이지 않으면 무한 루프 발생할수 있음

                                // true로 하면 특정 사이트에 접속하기위해 로그인 했지만 다시 메인페이지로 돌아감
                                .defaultSuccessUrl("/", false)

                                .failureUrl("/login-error")

                                .authenticationDetailsSource(customAuthDetails)
                )

                // 로그 아웃시 메인 페이지로 가도록 하기
                .logout( logout->logout.logoutSuccessUrl("/"))

                // 유저가 관리자 페이지에 접근할때 뜬 에러(403)시 띄울 페이지 연결
                .exceptionHandling(exception -> exception.accessDeniedPage("/access-denied"))
                ;
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 웹 리소스에 대해서는 시큐리티 필터가 작동하지 않도록 ignore
        web.ignoring()
                .requestMatchers(
                        PathRequest.toStaticResources().atCommonLocations()
                );

    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .inMemoryAuthentication()
                .withUser(
                        // 테스트에 한정에서 사용하는 메서드
                        User.withDefaultPasswordEncoder()
                                .username("user1")
                                .password("1111")
                                .roles("USER")
                ).withUser(
                        User.withDefaultPasswordEncoder()
                                .username("admin")
                                .password("2222")
                                .roles("ADMIN")
                );
    }
}

Home Controller

@Controller
public class HomeController {

    @GetMapping("/")
    public String main(){
        return "index";
    }

    @GetMapping("/login")
    public String login(){
        return "loginForm";
    }

    @GetMapping("/login-error")
    public String loginError(Model model){
        model.addAttribute("loginError", true);
        return "loginForm";
    }

    // CustomAuthDetails 확인
    // 각 build한 변수에 값이 들어간것을 확인할 수 있다
    @GetMapping("/auth")
    @ResponseBody // 이를 설정하여야 json 형태로 body가 내려감
    public Authentication auth(){
        return SecurityContextHolder.getContext().getAuthentication();
    }

    @GetMapping("/access-denied")
    public String accessDenied(){
        return "AccessDenied";
    }

    @PreAuthorize("hasAnyAuthority('ROLE_USER')")
    @GetMapping("/user-page")
    public String userPage(){
        return "UserPage";
    }

    @PreAuthorize("hasAnyAuthority('ROLE_ADMIN')")
    @GetMapping("/admin-page")
    public String adminPage(){
        return "AdminPage";
    }
}

thymeleaf 에서 security를 적용하는 태그

ex) ROLE_USER 시에만 보이게 되는 화면 구현

<div sec:authorize="isAuthenticated()">
  This content is only shown to authenticated users.
</div>
<div sec:authorize="hasRole('ROLE_ADMIN')">
  This content is only shown to administrators.
</div>
<div sec:authorize="hasRole('ROLE_USER')">
  This content is only shown to users.
</div>
profile
Journey for Backend Developer

0개의 댓글