source

Spring Security / SpringMVC에서 인증된 사용자를 수동으로 설정하는 방법

factcode 2022. 9. 29. 00:10
반응형

Spring Security / SpringMVC에서 인증된 사용자를 수동으로 설정하는 방법

새 사용자가 '새 계정' 양식을 제출한 후 해당 사용자가 다음 페이지에서 로그인할 필요가 없도록 수동으로 로그인하고 싶습니다.

스프링 보안 대행 수신기를 통과하는 일반 형식의 로그인 페이지는 정상적으로 작동합니다.

new-account-form 컨트롤러에서 Username Password를 만듭니다.인증토큰을 생성하여 SecurityContext에서 수동으로 설정합니다.

SecurityContextHolder.getContext().setAuthentication(authentication);

나중에 같은 페이지에서 사용자가 로그인하고 있는지 확인합니다.

SecurityContextHolder.getContext().getAuthentication().getAuthorities();

그러면 이전에 인증에서 설정한 권한이 반환됩니다.잘 있다.

그러나 로드하는 바로 다음 페이지에서 동일한 코드가 호출되면 인증 토큰은 UserAnonymous일 뿐입니다.

이전 요청에서 설정한 인증이 유지되지 않은 이유를 알 수 없습니다.무슨 생각 있어?

  • 세션 ID가 올바르게 설정되어 있지 않은 것과 관계가 있습니까?
  • 뭔가 내 인증을 덮어쓰는 것이 있습니까?
  • 인증을 저장하려면 다른 단계가 필요할 수도 있습니다.
  • 아니면 단일 요청이 아닌 세션 전체에 걸쳐 인증을 선언하기 위해 수행해야 하는 작업이 있습니까?

여기서 무슨 일이 일어나고 있는지 알 수 있는 생각들을 찾고 있어요.

다른 완전한 해결책을 찾을 수 없어서 게시물을 올리려고 했어요.이것은 다소 해킹일 수 있지만, 이 문제를 위의 문제로 해결했습니다.

public void login(HttpServletRequest request, String userName, String password)
{

    UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(userName, password);

    // Authenticate the user
    Authentication authentication = authenticationManager.authenticate(authRequest);
    SecurityContext securityContext = SecurityContextHolder.getContext();
    securityContext.setAuthentication(authentication);

    // Create a new session and add the security context.
    HttpSession session = request.getSession(true);
    session.setAttribute("SPRING_SECURITY_CONTEXT", securityContext);
}

나도 얼마 전에 너와 같은 문제가 있었어.자세한 것은 기억나지 않지만, 다음의 코드로 동작하고 있습니다.이 코드는 Spring Webflow 흐름 내에서 사용되므로 RequestContext 클래스 및 ExternalContext 클래스 내에서 사용됩니다.그러나 가장 관련이 있는 부분은 doAutoLogin 메서드입니다.

public String registerUser(UserRegistrationFormBean userRegistrationFormBean,
                           RequestContext requestContext,
                           ExternalContext externalContext) {

    try {
        Locale userLocale = requestContext.getExternalContext().getLocale();
        this.userService.createNewUser(userRegistrationFormBean, userLocale, Constants.SYSTEM_USER_ID);
        String emailAddress = userRegistrationFormBean.getChooseEmailAddressFormBean().getEmailAddress();
        String password = userRegistrationFormBean.getChoosePasswordFormBean().getPassword();
        doAutoLogin(emailAddress, password, (HttpServletRequest) externalContext.getNativeRequest());
        return "success";

    } catch (EmailAddressNotUniqueException e) {
        MessageResolver messageResolvable 
                = new MessageBuilder().error()
                                      .source(UserRegistrationFormBean.PROPERTYNAME_EMAIL_ADDRESS)
                                      .code("userRegistration.emailAddress.not.unique")
                                      .build();
        requestContext.getMessageContext().addMessage(messageResolvable);
        return "error";
    }

}


private void doAutoLogin(String username, String password, HttpServletRequest request) {

    try {
        // Must be called from request filtered by Spring Security, otherwise SecurityContextHolder is not updated
        UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password);
        token.setDetails(new WebAuthenticationDetails(request));
        Authentication authentication = this.authenticationProvider.authenticate(token);
        logger.debug("Logging in with [{}]", authentication.getPrincipal());
        SecurityContextHolder.getContext().setAuthentication(authentication);
    } catch (Exception e) {
        SecurityContextHolder.getContext().setAuthentication(null);
        logger.error("Failure in autoLogin", e);
    }

}

결국 문제의 근원을 알아냈다.

보안 콘텍스트를 수동으로 생성해도 Session 객체는 생성되지 않습니다.Spring Security 메커니즘은 요청 처리가 종료된 경우에만 세션오브젝트가 늘임을 인식합니다(요구가 처리된 후 보안 컨텍스트를 세션에 저장하려고 할 때).

요청 끝에 Spring Security가 새 세션 개체와 세션 ID를 만듭니다.단, 이 새로운 세션 ID는 브라우저에 대한 응답이 이루어진 후 요청 끝에 발생하기 때문에 브라우저에 도달하지 않습니다.이로 인해 다음 요청에 이전 세션 ID가 포함되어 있을 때 새 세션 ID(수동으로 로그온한 사용자를 포함하는 보안 컨텍스트)가 손실됩니다.

디버깅 로깅을 켜면 무슨 일이 일어나고 있는지 더 잘 알 수 있습니다.

브라우저 측 디버거를 사용하여 HTTP 응답으로 반환된 헤더를 확인하여 세션 쿠키가 설정되었는지 여부를 확인할 수 있습니다.(다른 방법도 있습니다.)

Spring Security가 안전한 세션쿠키를 설정하고 있고 요청된 다음 페이지에는 "https" URL이 아닌 "http" URL이 있을 수 있습니다(브라우저는 "http" URL에 대해 안전한 쿠키를 보내지 않습니다).

Servlet 2.4의 새로운 필터링 기능은 기본적으로 응용 프로그램서버에 의한 실제 요구 처리 전후의 요구 흐름에서만 필터가 동작할 수 있다는 제한을 완화합니다.대신 Servlet 2.4 필터는 모든 디스패치 포인트에서 요청 디스패처와 상호 작용할 수 있습니다.즉, 웹 리소스가 요청을 다른 리소스(예를 들어 동일한 응용 프로그램의 JSP 페이지로 요청을 전송하는 서블릿)로 전송할 때 대상 리소스에 의해 요청이 처리되기 전에 필터를 작동할 수 있습니다.또한 웹 리소스에 다른 웹 리소스로부터의 출력 또는 기능(예를 들어 다른 여러 JSP 페이지로부터의 출력을 포함하는 JSP 페이지)이 포함되어 있는 경우 Servlet 2.4 필터는 포함된 각 리소스 전후에 작동할 수 있습니다.

필요한 기능을 켜려면:

web.xml

<filter>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class> 
</filter>  
<filter-mapping>   
    <filter-name>springSecurityFilterChain</filter-name>   
    <url-pattern>/<strike>*</strike></url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

등록 컨트롤러

return "forward:/login?j_username=" + registrationModel.getUserEmail()
        + "&j_password=" + registrationModel.getPassword();

extjs 응용 프로그램을 테스트하려고 했는데 테스트 설정에 성공했습니다.인증명백한 원인도 없이 갑자기 작동을 멈춘 증거입니다.

위의 답변을 얻을 수 없었기 때문에 테스트 환경에서 스프링을 건너뛰는 것이 해결책이었습니다.봄 무렵에는 다음과 같은 솔기를 도입했습니다.

public class SpringUserAccessor implements UserAccessor
{
    @Override
    public User getUser()
    {
        SecurityContext context = SecurityContextHolder.getContext();
        Authentication authentication = context.getAuthentication();
        return (User) authentication.getPrincipal();
    }
}

여기서 사용자는 사용자 지정 유형입니다.

그런 다음 테스트 코드를 스프링 아웃할 수 있는 옵션이 있는 클래스로 포장합니다.

public class CurrentUserAccessor
{
    private static UserAccessor _accessor;

    public CurrentUserAccessor()
    {
        _accessor = new SpringUserAccessor();
    }

    public User getUser()
    {
        return _accessor.getUser();
    }

    public static void UseTestingAccessor(User user)
    {
        _accessor = new TestUserAccessor(user);
    }
}

테스트 버전은 다음과 같습니다.

public class TestUserAccessor implements UserAccessor
{
    private static User _user;

    public TestUserAccessor(User user)
    {
        _user = user;
    }

    @Override
    public User getUser()
    {
        return _user;
    }
}

호출 코드에서 데이터베이스에서 로드된 적절한 사용자를 계속 사용하고 있습니다.

    User user = (User) _userService.loadUserByUsername(username);
    CurrentUserAccessor.UseTestingAccessor(user);

보안을 실제로 사용해야 하는 경우에는 이 방법이 적합하지 않지만, 저는 테스트 전개를 위해 무보안 설정을 실행하고 있습니다.다른 사람도 비슷한 상황에 처할 거라고 생각했어요.이 패턴은 이전에 정적 의존성을 배제하기 위해 사용한 적이 있습니다.다른 대안은 래퍼 클래스의 정적인 상태를 유지할 수 있지만 CurrentUserAccessor를 필요한 클래스에 전달해야 하기 때문에 코드의 의존성이 더 명확하기 때문에 이 클래스가 좋습니다.

언급URL : https://stackoverflow.com/questions/4664893/how-to-manually-set-an-authenticated-user-in-spring-security-springmvc

반응형