source

커스텀 Angular를 사용한 스프링 부트 및 보안JS 로그인 페이지

factcode 2023. 3. 5. 21:58
반응형

커스텀 Angular를 사용한 스프링 부트 및 보안JS 로그인 페이지

커스텀 Angular를 구현하고 있습니다.Spring Security용 JS 로그인 페이지 및 인증에 문제가 있습니다.

이 튜토리얼/예시에 따라, 그 는 로컬로 정상적으로 동작합니다.

단, 직접 실장하려고 하면 인증이 실패합니다.제 실수가 어디에 있는지 모르겠어요.

POST가 credential로 /login(컬은 예와 동일)되어 GET /login/로 리다이렉트된 302 Found가 수신되고 404 Not Found가 반환됩니다.

/login에 POST를 시도해도 Spring은 디버깅로그를 생성하지 않습니다.그래서 나는 그것이 302를 어떻게 서비스하고 있는지 잘 모르겠다.

내 코드는 다음 URL에서 찾을 수 있습니다.

주목할 만한 변경 사항(및 문제의 원인일 가능성이 높다):

  • 파일 구조 변경

  • 엄밀하게 각진 사용(No jQuery) - POST 요청을 작성하기 위해 다른 기능이 필요합니다.

  • wro4j 대신 bower 사용

  • 각도 코드 스타일링/스코핑

스프링 보안 관련 질문의 대부분은 POST 요청의 형식이 올바르지 않다는 것을 나타냅니다만, 저는 예시와 같은 것 같습니다(적어도 Chrome 개발 콘솔에서 컬을 복사하는 경우).커스텀 인증 프로바이더를 도입할 것을 제안하고 있습니다만, 이 예에서는 필요 없기 때문에, 제 것과 이 예제의 차이가 무엇인지 알 수 없습니다.스택 익스체인지 좀 도와줘, 내 유일한 희망이야.

개발 도구: imgurDOTcom/a/B2KmV

관련 코드:

login.displays(로그인

'use strict';
angular
    .module('webApp')
    .controller('LoginCtrl', ['$root`enter code here`Scope', '$scope', '$http', '$location', '$route', function($rootScope, $scope, $http, $location, $route) {
        console.log("LoginCtrl created.");

        var vm = this;
        vm.credentials = {
            username: "",
            password: ""
        };
        //vm.login = login;

        $scope.tab = function(route) {
            return $route.current && route === $route.current.controller;
        };

        var authenticate = function(callback) {

            $http.get('user').success(function(data) {
                console.log("/user success: " + JSON.stringify(data));
                if (data.name) {
                    console.log("And Authenticated!");
                    $rootScope.authenticated = true;
                } else {
                    console.log("But received invalid data.");
                    $rootScope.authenticated = false;
                }
                callback && callback();
            }).error(function(response) {
                console.log("/user failure." + JSON.stringify(response));
                $rootScope.authenticated = false;
                callback && callback();
            });

        };

        authenticate();

        $scope.login = function() {

            var data2 = 'username=' + encodeURIComponent(vm.credentials.username) +
                '&password=' + encodeURIComponent(vm.credentials.password);

            $http.post('login', data2, {
                headers : {
                    'Content-Type': 'application/x-www-form-urlencoded'
                }
            }).success(function() {
                authenticate(function() {
                    if ($rootScope.authenticated) {
                        console.log("Login succeeded");
                        $location.path("/");
                        $scope.error = false;
                        $rootScope.authenticated = true;
                    } else {
                        console.log("Login failed with redirect");
                        $location.path("/login");
                        $scope.error = true;
                        $rootScope.authenticated = false;
                    }
                });
            }).error(function() {
                console.log("Login failed");
                $location.path("/login");
                $scope.error = true;
                $rootScope.authenticated = false;
            })
        };

        $scope.logout = function() {
            $http.post('logout', {}).success(function() {
                $rootScope.authenticated = false;
                $location.path("/");
            }).error(function() {
                console.log("Logout failed");
                $rootScope.authenticated = false;
            });
        }

    }]);

어플.자바

package com.recursivechaos.springangularstarter;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.csrf.CsrfFilter;
import org.springframework.security.web.csrf.CsrfToken;
import org.springframework.security.web.csrf.CsrfTokenRepository;
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.filter.OncePerRequestFilter;
import org.springframework.web.util.WebUtils;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.security.Principal;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

@SpringBootApplication
@RestController
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @RequestMapping("/user")
    public Principal user(Principal user) {
        return user;
    }

    @RequestMapping("/resource")
    public Map<String, Object> home() {
        Map<String, Object> model = new HashMap<>();
        model.put("id", UUID.randomUUID().toString());
        model.put("content", "Hello World");
        return model;
    }

    @Configuration
    @Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
    protected static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.
                formLogin().
                //loginPage("/#/login").
            and().
                logout().
            and().
                authorizeRequests().
                antMatchers("/index.html", "/home/**", "/login/**", "/bower_components/**", "/", "/main.js", "/login/", "/navigation/**","/login","login/","/login.html").
                permitAll().
                anyRequest().
                authenticated().
            and().
                csrf().
                csrfTokenRepository(csrfTokenRepository()).
            and().
                addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
        }

        private Filter csrfHeaderFilter() {
            return new OncePerRequestFilter() {
                @Override
                protected void doFilterInternal(HttpServletRequest request,
                                                HttpServletResponse response, FilterChain filterChain)
                    throws ServletException, IOException {
                    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class
                        .getName());
                    if (csrf != null) {
                        Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
                        String token = csrf.getToken();
                        if (cookie == null || token != null
                            && !token.equals(cookie.getValue())) {
                            cookie = new Cookie("XSRF-TOKEN", token);
                            cookie.setPath("/");
                            response.addCookie(cookie);
                        }
                    }
                    filterChain.doFilter(request, response);
                }
            };
        }

        private CsrfTokenRepository csrfTokenRepository() {
            HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
            repository.setHeaderName("X-XSRF-TOKEN");
            return repository;
        }
    }

}

WebSecuritConfigAdapter 추가 시도

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
        httpSecurity
            .authorizeRequests()
            .antMatchers("/**").permitAll()
            .anyRequest().authenticated();
    }
}

login.js에서 호출되는 것이1개 있어요authenticate()사용자가 /user를 호출하면 GET /login/로 리다이렉트 됩니다.스프링은 존재하지 않는 login.jsp를 검색하여 404 Not Found로 끝납니다.

다음의 순서로 동작시킬 수 있습니다.

1) 호출 제거authenticate()38번 회선부터 로그인 합니다.js

2) 다음과 같은 로그인 처리 URL을 추가합니다.

http.
     formLogin().
     loginProcessingUrl("/perform_login").
     and().
     logout()
 ....

3) 로그인 URL을 다음과 같이 'perform_login'으로 변경합니다.

$http.post('perform_login', data2, {
            headers : {
                'Content-Type': 'application/x-www-form-urlencoded'
            }
        })....

작동하면 사용자를 얻을 수 있습니다.

스프링 보안 설정에 대해서는, http://www.baeldung.com/spring-security-login 를 참조해 주세요.

이런 종류의 오류는 스프링보안 설정 문제일 가능성이 높습니다.

당신의 봄 보안을 읽었을 때, 'loginPage'라는 코멘트가 있습니다.
또, 다음과 같이 합니다.

antMatchers("/index.html", "/home/**", "/login/**", "/bower_components/**", "/", "/main.js", "/login/", "/navigation/**","/login","login/","/login.html")

이상하게 들리네요

antMatchers("/index.html", "/home**", "/login**", "/bower_components**", "/main.js", "/navigation**")

괜찮을 거야.

그리고 저는 Angular를 별로 좋아하지 않지만, 당신의 authenticate() 메서드는 정의 직후에 호출되어 당신의 'permitAll' 매처에는 없는 'user'에서 GET을 수행합니다.

그러니 다른 방법을 생각해 보세요.매처를 추가할수록 사용자 데이터에 자유롭게 액세스할 수 있도록 하는 것은 좋지 않습니다.또는 인증 후 사용자 정보를 가져옵니다.

건배.

인증을 추가해 볼 수 있습니까?요청을 리다이렉트하는 기본 스프링 성공 핸들러를 재정의하는 SuccessHandler

private AuthenticationSuccessHandler successHandler() {
    return new AuthenticationSuccessHandler() {
      @Override
      public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException {
        httpServletResponse.getWriter().append("OK");
        httpServletResponse.setStatus(200);
      }
    };
  }

설정에 인증 성공 핸들러를 추가합니다.

http.
                formLogin().successHandler(successHandler())
            and().
                logout().
            and().
                authorizeRequests().
                antMatchers("/index.html", "/home/**", "/login/**", "/bower_components/**", "/", "/main.js", "/login/", "/navigation/**","/login","login/","/login.html").
                permitAll().
                anyRequest().
                authenticated().
            and().
                csrf().
                csrfTokenRepository(csrfTokenRepository()).
            and().
                addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);
  1. 스프링 로깅 추가 활성화: application.properties를 만들고 다음을 입력합니다.

logging.level.ROOT=DEBUG전체 인증 프로세스 세부 정보와 실제 오류가 표시됩니다.

  1. CSRF 보호가 유효하게 되어 있다.

    and().csrf(). csrfTokenRepository(csrfTokenRepository()). and(). addFilterAfter(csrfHeaderFilter(), CsrfFilter.class);

    CSRF 토큰은 url 파라미터가 아닌 cookie에서 추출됩니다.

    CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class .getName()); if (csrf != null) { Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN"); String token = csrf.getToken(); if (cookie == null || token != null && !token.equals(cookie.getValue())) {

따라서 이 경우 cookie 값도 요청과 함께 제공되는지 확인해야 합니다.

언급URL : https://stackoverflow.com/questions/28460071/spring-boot-and-security-with-custom-angularjs-login-page

반응형