[Spring Security] 온라인 시험 사이트 구현(4. 사이트 권한)

WOOK JONG KIM·2022년 12월 9일
0

패캠_java&Spring

목록 보기
93/103
post-thumbnail

DBInit

@Component
@RequiredArgsConstructor
public class DBInit implements CommandLineRunner {

    private final UserService userService;
    private final SchoolService schoolService;
    private final PasswordEncoder passwordEncoder;

    @Override
    public void run(String... args) throws Exception {
        School defaultSchool = schoolService.findSchool(1L).orElseGet(()->
            schoolService.save(School.builder()
                    .name("테스트 학교")
                    .city("서울")
                    .build())
        );

        userService.findByEmail("admin@test.com").or(()->{
            User admin = User.builder()
                    .name("admin")
                    .email("admin@test.com")
                    .password(passwordEncoder.encode("1234"))
                    .enabled(true)
                    .school(defaultSchool)
                    .build();
            admin = userService.save(admin);
            admin.setAuthorities(Set.of(
                    new Authority(admin.getUserId(), Authority.ROLE_ADMIN),
                    new Authority(admin.getUserId(), Authority.ROLE_TEACHER),
                    new Authority(admin.getUserId(), Authority.ROLE_STUDENT)));
            return Optional.of(userService.save(admin));
        });
        userService.findByEmail("teacher@test.com").or(()->{
            User teacher = User.builder()
                    .name("teacher")
                    .email("teacher@test.com")
                    .password(passwordEncoder.encode("1234"))
                    .enabled(true)
                    .school(defaultSchool)
                    .build();
            teacher = userService.save(teacher);
            teacher.setAuthorities(Set.of(
                    new Authority(teacher.getUserId(), Authority.ROLE_TEACHER)
            ));
            return Optional.of(userService.save(teacher));
        });
        userService.findByEmail("study@test.com").or(()->{
            User study = User.builder()
                    .name("study")
                    .email("study@test.com")
                    .password(passwordEncoder.encode("1234"))
                    .enabled(true)
                    .school(defaultSchool)
                    .build();
            study = userService.save(study);
            study.setAuthorities(Set.of(
                    new Authority(study.getUserId(), Authority.ROLE_STUDENT)
            ));
            return Optional.of(userService.save(study));
        });
    }
}
public class LoginFailureHandler implements AuthenticationFailureHandler {

    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    protected Log logger = LogFactory.getLog(this.getClass());

    @Override
    public void onAuthenticationFailure(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException exception
    ) throws IOException, ServletException {
        handle(request, response);
        clearAuthenticationAttributes(request);
    }

    protected void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }


    protected void handle(
            HttpServletRequest request,
            HttpServletResponse response
    ) throws IOException {
        String targetUrl = determineTargetUrl(request);
        if (response.isCommitted()) {
            logger.debug("Response has already been committed. Unable to redirect to "+ targetUrl);
            return;
        }
        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(final HttpServletRequest request) {
        if(request.getParameter("site").equals("manager")) {
            return "/login?site=manager&error=true";
        }else if(request.getParameter("site").equals("study")){
            return "/login?site=study&error=true";
        }else if(request.getParameter("site").equals("teacher")){
            return "/login?site=teacher&error=true";
        }
        return "/";
    }


}
public class LoginSuccessHandler implements AuthenticationSuccessHandler {

    private RequestCache requestCache = new HttpSessionRequestCache();
    private RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
    protected Log logger = LogFactory.getLog(this.getClass());

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request,
                                        HttpServletResponse response,
                                        Authentication authentication)
            throws IOException {

        handle(request, response, requestCache.getRequest(request, response), authentication);
        clearAuthenticationAttributes(request);
    }

    @Override
    public void onAuthenticationSuccess(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain,
            Authentication authentication
    ) throws IOException, ServletException {
//        System.out.println("success... 1");
    }

    protected void clearAuthenticationAttributes(HttpServletRequest request) {
        HttpSession session = request.getSession(false);
        if (session == null) {
            return;
        }
        session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
    }


    protected void handle(
            HttpServletRequest request,
            HttpServletResponse response,
            SavedRequest savedRequest,
            Authentication authentication
    ) throws IOException {
        String targetUrl = determineTargetUrl(request, savedRequest, authentication);
        if (response.isCommitted()) {
            logger.debug("Response has already been committed. Unable to redirect to "+ targetUrl);
            return;
        }
        redirectStrategy.sendRedirect(request, response, targetUrl);
    }

    protected String determineTargetUrl(final HttpServletRequest request, SavedRequest savedRequest, final Authentication authentication) {
        if(savedRequest != null) {
            String redirectUrl = savedRequest.getRedirectUrl();
            if(redirectUrl != null && !redirectUrl.startsWith("/login")) {
                return savedRequest.getRedirectUrl();
            }
        }
        if(request.getParameter("site").equals("manager")) {
            return "/manager";
        }else if(request.getParameter("site").equals("study")){
            return "/study";
        }else if(request.getParameter("site").equals("teacher")){
            return "/teacher";
        }
        return "/";
    }

}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@RequiredArgsConstructor
public class OnlinePaperSecurityConfig extends WebSecurityConfigurerAdapter {

    private final UserSecurityService userSecurityService;

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

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userSecurityService)
                .passwordEncoder(passwordEncoder());
    }

    private RememberMeServices rememberMeServices(){
        TokenBasedRememberMeServices rememberMeServices = new TokenBasedRememberMeServices(
                "paper-site-remember-me",
                userSecurityService
        );
        rememberMeServices.setParameter("remember-me");
        rememberMeServices.setAlwaysRemember(true);
        rememberMeServices.setTokenValiditySeconds(3600);
        return rememberMeServices;
    }


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        final SpLoginFilter filter = new SpLoginFilter(
                authenticationManagerBean(),
                rememberMeServices()
        );
        http
                .csrf().disable()
                .formLogin(login->{
                    login.loginPage("/login")
                    ;
                })
                .logout(logout->{
                    logout.logoutSuccessUrl("/")
                    ;
                })
                .rememberMe(config->{
                            config.rememberMeServices(rememberMeServices())
                            ;
                })
                .addFilterAt(filter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling(exception->{
                    exception.accessDeniedPage("/access-denied");
                })
                .authorizeRequests(config->{
                    config
                            .antMatchers("/").permitAll()
                            .antMatchers("/login").permitAll()
                            .antMatchers("/error").permitAll()
                            .antMatchers("/signup/*").permitAll()
                            .antMatchers("/study/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_STUDENT")
                            .antMatchers("/teacher/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_TEACHER")
                            .antMatchers("/manager/**").hasAuthority("ROLE_ADMIN")
                    ;
                })
        ;
    }


    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring()
                .requestMatchers(PathRequest.toStaticResources().atCommonLocations());
    }
}
public class SpLoginFilter extends UsernamePasswordAuthenticationFilter {

    private final AuthenticationManager authenticationManager;

    public SpLoginFilter(
            AuthenticationManager authenticationManager,
            RememberMeServices rememberMeServices
    ){
        this.authenticationManager = authenticationManager;
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/login","POST"));
        this.setAuthenticationSuccessHandler(new LoginSuccessHandler());
        this.setAuthenticationFailureHandler(new LoginFailureHandler());
        this.setRememberMeServices(rememberMeServices);
    }

    @SneakyThrows
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        UserLogin userLogin = UserLogin.builder()
                .username(request.getParameter("username"))
                .password(request.getParameter("password"))
                .site(request.getParameter("site"))
                .rememberme(request.getParameter("remember-me") != null)
                .build();
        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                userLogin.getUsername(), userLogin.getPassword(), null
        );
        return authenticationManager.authenticate(authToken);
    }

    @Override
    protected void successfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            FilterChain chain,
            Authentication authResult) throws IOException, ServletException
    {
        super.successfulAuthentication(request, response, chain, authResult);
    }

    @Override
    protected void unsuccessfulAuthentication(
            HttpServletRequest request,
            HttpServletResponse response,
            AuthenticationException failed) throws IOException, ServletException
    {
        super.unsuccessfulAuthentication(request, response, failed);
    }

    public static String getIp(HttpServletRequest request) {
        String ip = request.getHeader("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
@Data
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class UserLogin {

    private String username;
    private String password;
    private String site;
    private boolean rememberme;

}

Controller의 HomeController

@Controller
@RequiredArgsConstructor
public class HomeController {

    private final SchoolService schoolService;
    private final UserService userService;
    private final PasswordEncoder passwordEncoder;

    private RequestCache requestCache = new HttpSessionRequestCache();

    @GetMapping("/")
    public String home(Model model){
        return "index";
    }

    @ResponseBody
    @GetMapping(value="/schools")
    public List<School> getSchoolList(@RequestParam(value="city", required = true) String city){
        return schoolService.getSchoolList(city);
    }

    @ResponseBody
    @GetMapping(value="/teachers")
    public List<UserData> getTeacherList(@RequestParam(value="schoolId", required = true) Long schoolId){
        return userService.findBySchoolTeacherList(schoolId).stream()
                .map(user->new UserData(user.getUserId(), user.getName()))
                .collect(Collectors.toList());
    }

    @GetMapping("/login")
    public String login(
            @AuthenticationPrincipal User user,
            @RequestParam(value="site", required = false) String site,
            @RequestParam(value="error", defaultValue = "false") Boolean error,
            HttpServletRequest request,
            Model model
    ){
        if(user!=null && user.isEnabled()){
            if(user.getAuthorities().contains(Authority.ADMIN_AUTHORITY)){
                return "redirect:/manager";
            }else if(user.getAuthorities().contains(Authority.TEACHER_AUTHORITY)){
                return "redirect:/teacher";
            }else if(user.getAuthorities().contains(Authority.STUDENT_AUTHORITY)){
                return "redirect:/study";
            }
        }
        if(site == null) {
            SavedRequest savedRequest = requestCache.getRequest(request, null);
            if(savedRequest != null) {
                site = estimateSite(savedRequest.getRedirectUrl());
            }
        }
        model.addAttribute("error", error);
        model.addAttribute("site", site);

        return "loginForm";
    }

    private String estimateSite(String referer) {
        if(referer == null)
            return "study.html";
        try {
            URL url = new URL(referer);
            String path = url.getPath();
            if(path != null){
                if(path.startsWith("/teacher")) return "teacher";
                if(path.startsWith("/study")) return "study";
                if(path.startsWith("/manager")) return "manager";
            }
            String query = url.getQuery();
            if(query != null){
                if(path.startsWith("/site=teacher")) return "teacher";
                if(path.startsWith("/site=study")) return "study";
                if(path.startsWith("/site=manager")) return "manager";
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        return "study.html";
    }

//    @PostMapping("/login")
//    public String loginPost(@RequestParam String site, Model model){
//        model.addAttribute("site", site);
//
//        return "redirect:/"+site;
//    }

    @GetMapping("/signup")
    public String signUp(
            @RequestParam String site,
            HttpServletRequest request
    ){
        if(site == null) {
            site = estimateSite(request.getParameter("referer"));
        }
        return "redirect:/"+site+"/signup";
    }

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

}

권한별 Controller 따로 구현해 둔것은 Github 참고하기!

profile
Journey for Backend Developer

0개의 댓글