11

我試圖在用戶在Spring Security中登錄後實施所需的操作屏幕?我要求用戶必須執行以完成表單(更改密碼,接受使用條款等),然後一旦用戶完成該操作,他就可以使用應用程序的其餘部分。我在使用Spring Security流的登錄屏幕上使用Spring OAuth2。Spring安全和登錄後需要採取措施

到目前爲止,我已嘗試使用http.formLogin().successHandler()自定義實現SavedRequestAwareAuthenticationSuccessHandler,它檢測用戶是否有必要的操作,然後當用戶填寫表單時將用戶重定向到頁面,但問題在於如果用戶導航離開該頁面,他將登錄到應用程序,並可以在不跳過表單的情況下使用它。但是我想要做的是阻止用戶建立會話,直到完成「需要操作」表單爲止。一旦完成,用戶應該自動登錄(例如,如果用戶要求只同意使用條款,他應該在第二次輸入密碼的情況下登錄)

這是我的代碼到目前爲止,自定義處理程序:

public class CustomLoginSuccessHandler extends SavedRequestAwareAuthenticationSuccessHandler { 

    @Autowired 
    UserService userService; 

    public final static String TARGET_URL_SESSION_ATTR_NAME = "target-url"; 

    public CustomLoginSuccessHandler(String defaultTargetUrl) { 
     setDefaultTargetUrl(defaultTargetUrl); 
    } 

    @Override 
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws ServletException, IOException { 
     HttpSession session = request.getSession(); 


     AuthorityUser authorityUser = (AuthorityUser)authentication.getPrincipal(); 

     String userId = authorityUser.getUserId(); 

     User u = userService.getById(userId); 

     Boolean changeRequiredDob = u.getChangeRequiredDob(); 
     Boolean changeRequiredPwd = u.getChangeRequiredPwd(); 
     Boolean changeRequiredTou = u.getChangeRequiredTou(); 

     if(changeRequiredDob || changeRequiredPwd || changeRequiredTou){ 

      String targetUrl = determineTargetUrl(request, response); 
      session.setAttribute(TARGET_URL_SESSION_ATTR_NAME, targetUrl); 
      getRedirectStrategy().sendRedirect(request, response, "/action-required"); 
     } else { 
      super.onAuthenticationSuccess(request, response, authentication); 
     } 
    } 
} 

然後,一旦它成功地完成我重定向用戶TARGET_URL_SESSION_ATTR_NAME已存儲到會話中。

這將是也有利於知道如何建立的會話期間檢測和重定向用戶到所需的操作屏幕(如果用戶登錄,後來當他登錄管理員設置動作所需的標誌在他的賬戶)。

+0

在一個普通的過濾器實現這個邏輯(映射到/ *)同時滿足您的requrements:1)用戶將無法導航遠離它,以及b)用戶將自動「登錄」,或而是通過了。只有您可能需要執行的其他事情是成功重定向。 – chimmi

+0

是否有一個實際的原因,您不想馬上創建會話? – chimmi

回答

3

https://github.com/king-julien/spring-oauth2-customfilter這是帶有授權和資源服務器的工作示例。此資源服務器(香草)是一個基本的無狀態應用程序,除非您接受服務條款(接受服務條款,只是在/ tos端點上執行POST),否則不會繼續進行任何操作。

創建一個過濾器

@Component 
public class TosFilter extends OncePerRequestFilter{ 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) 
      throws ServletException, IOException { 
     System.out.println(request.getRequestURI()); 

     // In realworld scenario HelloWorldController.acceptedTOS is a persisted value rather than a static variable 
     if(!HelloWorldController.acceptedTOS){ 
      //response.sendRedirect("/no-tos"); 
      request.getRequestDispatcher("error-no-tos").forward(request, response); 
     } 
     filterChain.doFilter(request,response); 
    } 
} 

註冊該過濾器

@Configuration 
public class SecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    TosFilter rolesFilter; 

    @Override 
    public void configure(HttpSecurity httpSecurity) throws Exception{ 

     httpSecurity 
       .addFilterAfter(rolesFilter, AbstractPreAuthenticatedProcessingFilter.class) 
       .csrf().disable() 
       .authorizeRequests().anyRequest().permitAll(); 
    } 
} 

註釋與@EnableResourceServer你的主。

@SpringBootApplication 
@EnableResourceServer 
public class Application { 

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

} 
1

我們解決的辦法是讓OAuth2用戶批准頁面是單頁的應用程序。 默認情況下,批准頁面控制器是WhitelabelApprovalEndpoint。我們通過定義自己的覆蓋「/ oauth/confirm_access」的OauthApproval控制器來覆蓋這個,所以我們可以在模型中添加額外的東西。加載批准(jsp)頁面後,我們將一些模型屬性轉換爲JavaScript變量(var token ='$ {_ csrf.token}';),然後啓動一個AngularJS應用程序。審批頁隨後可以做任何事情(在顯示實際審批表之前),我們只需要爲不同的功能構建REST端點。

記住@SessionAttributes(「authorizationRequest」)添加到控制器

+0

我不熟悉OAuth2,但是這並不意味着自定義操作必須由授權服務器而不是資源服務器來處理? – chimmi

1

而不是AuthenticationSuccessHandler你應該使用過濾器:

public class ActionRequirementCheckingFilter extends OncePerRequestFilter { 

    /* This matcher should not match static resources (js,css etc), 
    * url`s needed to handle the action and possibly something else, 
    * depending on your application */ 
    private RequestMatcher matcher; 

    @Override 
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { 
     HttpSession session = request.getSession(); 
     Boolean actionRequired = false; 

     /* calculate actual value for actionRequired */ 

     if(matcher.matches(request) && actionRequired){ 

      /* save current request info into session for later use if needed */ 

      response.sendRedirect("/action-required"); 
     } else { 
      filterChain.doFilter(request, response); 
     } 
    } 

} 

這種方法適合所有的質量要求:

  • 用戶將無法從它
  • 用戶將被自動已登錄導航離開在動作完成後
  • 它甚至可以用於現有會話

唯一的缺點是會話將在動作完成之前創建,但除非您有真正的理由不這樣做(即使我不能這樣做),這是微不足道的。

相關問題