Spring Security 3 Ajax登录–访问受保护的资源

我看过一些有关Spring Security 3 Ajax登录的博客,但是我找不到解决如何调用基于Ajax的登录的博客,匿名用户正在Ajax中访问受保护的资源。

问题 – Web应用程序允许匿名访问某些部分,并且某些部分是受保护的资源,需要用户登录。

当匿名用户(通过Http Get / Post)访问受保护的资源时,Spring Security会自动调用登录页面,并在成功通过身份验证后重定向到所需的资源/页面。

但是,如果正在Ajax中访问受保护的资源,则登录页面将无法正确显示(将在页面的一部分上进行设置)。 302代码(重定向到登录页面)将无法在Ajax中正常运行。

请注意,这与启动Ajax登录屏幕不同(例如,当用户按下登录按钮并调用带有用户/密码字段的弹出窗口时)。

那么–我们如何让Spring Security 3通过“常规” HTTP Post(基于FORM的身份验证)和Ajax调用来处理对受保护资源的访问,包括在成功身份验证后重定向到所需资源?

因此,此博客文章包含两个保护层/部分:
1. Spring Security 3标准基于FORM的身份验证
2.配置/扩展Spring Security 3.并且该应用程序还支持Ajax对受保护资源的访问。

关于第1部分-有关此问题的参考很多。 无需详细说明。

关于第2部分–要求以下内容:

1.配置Spring Security 3以启用基于Ajax的登录。
2.将客户端Ajax调用配置为受保护的资源,以处理身份验证请求。
3.重新执行功能以模拟成功登录后自动进行用户原始方法的调用(这在基于FORM的登录中发生)

下图描述了详细的流程,应有助于遵循客户端/服务器通信。

通过Ajax处理受保护的资源访问

让我们讨论一下图:

该流程始于对受保护资源(1)的匿名用户Ajax请求。 在这种情况下,用户希望将商品添加到购物车。

addItem方法是受保护的资源,它通过Spring Security(@pre_authorize(“ SOME_ROLE”))(2)受保护。 这使Spring Secutiry过滤器(3)发送带有HTTP代码302的登录表单(即,重定向到该页面)。

现在,由于这是一个Ajax调用,它将无法很好地处理请求,因此这里涉及到了登录表单,将其放在一边,然后调用基于Ajax的登录(4):

客户端Ajax方法(调用了Ajax addItem方法)检查​​它是基于表单的登录名还是其他任何答复。 如果是基于FORM的登录,它将调用一个对话框模式(5),该模式将尝试登录Ajax。 Spring将处理Ajax登录认证(6)并将适当的消息返回给客户端。 如果消息成功,则客户端将重新执行原始功能,该功能试图访问受保护的资源(例如,本例中的addItem )。

让我们看看它们如何适合我们的代码:
步骤#1,#4 –客户端访问受保护的资源并检查是否需要登录

//JavaScript method - Ajax call to protected resource (#1 in flow diagram)
function addItem(itemId) {    
    $.ajax({
        url: '/my_url/order/addItem',
        type: 'POST',
        data: ({orderItemId : itemId,...}),               
        success: function(data) {

           //construct a callback string if user is not logged in.
           var cllbck = 'addItem('+itemId +')';

           //Client check if login required
           //(#4 in flow diagram)
           if (verifyAuthentication(data,cllbck)){
               // in here => access to protected resource was ok
               // show message to user, "item has been added..."
           }
      });
    }

步骤#2,#3 –是常规的Spring Security配置。 的大量资源 那里

步骤#4 –客户端检查是否需要登录:

function verifyAuthentication(data, cllBackString){
   //naive check - I put a string in the login form, so I check for existance
   if (isNaN(data) && (data.indexOf("login_hidden_for_ajax")!= -1)){
      //if got here then data is a loginform => login required
      
      //set callback in ajax login form hidden input  
      $("#my_callback").val(cllBackString); 
 
      //show ajax login
      //Get the window height and width
      var winH = $(window).height();
      var winW = $(window).width();
              
      //Set the popup window to center
      $("#ajaxLogin").css('top',  winH/2-$("#ajaxLogin").height()/2);
      $("#ajaxLogin").css('left', winW/2-$("#ajaxLogin").width()/2);
      $("#ajaxLogin").fadeIn(2000); 
      return false;
      } 
    // data is not a login form => return true to continue with function processing
    return true; 
}

步骤#5,#7 – Ajax登录表单使用以下Ajax登录:

function ajaxLogin(form, suffix){
 
 var my_callback = form.my_callback.value; // The original function which accessed the protected resource
 var user_pass = form.j_ajax_password.value;
 var user_name = form.j_ajax_username.value; 

//Ajax login - we send credentials to j_spring_security_check (as in form based login
 $.ajax({
          url: "/myContextURL/j_spring_security_check",    
          data: { j_username: user_name , j_password: user_pass }, 
          type: "POST",
          beforeSend: function (xhr) {
             xhr.setRequestHeader("X-Ajax-call", "true");
          },
          success: function(result) {     
          //if login is success, hide the login modal and
          //re-execute the function which called the protected resource
          //(#7 in the diagram flow)
       if (result == "ok") {
 
            $("#ajax_login_error_"+ suffix).html("");            
         $('#ajaxLogin').hide();
         if (my_callback!=null && my_callback!='undefined' && my_callback!=''){
      eval(my_callback.replace(/_/g,'"'));
         }
         
            return true;
          }else {        
         
         $("#ajax_login_error_"+ suffix).html('<span  class="alert display_b clear_b centeralign">Bad user/password</span>') ;
         return false;         
        }
    },
    error: function(XMLHttpRequest, textStatus, errorThrown){
     $("#ajax_login_error_"+ suffix).html("Bad user/password") ;
     return false; 
    }
});
}

我们需要将Spring设置为支持Ajax登录(#6):

设置Spring Security xml配置:

<beans:beans xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/security" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.0.3.xsd">
 
    
    <http auto-config="false" use-expressions="true">
        <intercept-url access="hasRole('ROLE_ADMIN')" pattern="/admin**">
        <intercept-url filters="none" pattern="/**">
        <intercept-url access="permitAll" pattern="/signin/**">
         
        <form-login authentication-failure-handler-ref="ajaxAuthenticationFailureHandler" authentication-success-handler-ref="ajaxAuthenticationSuccessHandler" login-page="/common/authentication/login"> 
        <logout invalidate-session="true" logout-success-url="/common/authentication/logout">
                     
        <custom-filter before="LOGOUT_FILTER" ref="logoutFilter">
 
    </custom-filter></logout></form-login></intercept-url></intercept-url></intercept-url></http>
     
    ...
</beans:beans>

定义成功登录的处理程序:

@Component("ajaxAuthenticationSuccessHandler")
public class AjaxAuthenticationSuccessHandler extends SimpleUrlAuthenticationSuccessHandler { 
    
    public AjaxAuthenticationSuccessHandler() {    
    }

 @Override
 public void onAuthenticationSuccess(HttpServletRequest request,
   HttpServletResponse response, Authentication authentication)
   throws IOException, ServletException { 
  
  HttpSession session = request.getSession();  
  DefaultSavedRequest defaultSavedRequest = (DefaultSavedRequest) session.getAttribute(WebAttributes.SAVED_REQUEST);
  //check if login is originated from ajax call
  if ("true".equals(request.getHeader("X-Ajax-call"))) {
         try {
          response.getWriter().print("ok");//return "ok" string
          response.getWriter().flush();
  } catch (IOException e) {    
     //handle exception...
  }
     } else {      
      setAlwaysUseDefaultTargetUrl(false);  
  ...
     }
 }
}

为登录失败定义一个处理程序–与成功相同,但是字符串为“ not-ok”。

我知道这里的某些代码不是最佳做法,所以我想听听您的想法。
如果您能看到改进流程或使其更通用的方法,请发给我。

鸣谢:通过gliffy完成了图表-在线图表工具

参考: Spring security 3 Ajax登录–通过 Gal Levinsky博客博客中的JCG合作伙伴 Gal Levinsky 访问受保护的资源


翻译自: https://www.javacodegeeks.com/2012/08/spring-security-3-ajax-login-accessing.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值