如何在 Grails 和 AngularJS 上使用 Spring Security 进行 Ajax 登录

Posted

技术标签:

【中文标题】如何在 Grails 和 AngularJS 上使用 Spring Security 进行 Ajax 登录【英文标题】:How to do Ajax login with Spring Security on Grails and AngularJS 【发布时间】:2015-12-30 20:13:58 【问题描述】:

我正在尝试创建向服务器发送 Ajax 请求以进行登录的用户表单。

我来自 Angular 的 POST 函数如下所示:

$http(
    method: 'POST',
    url: '/j_spring_security_check',
    data: j_username: credentials.username, j_password: credentials.password,
    params: ajax: true
)
    .then(function (data) 
        $rootScope.authenticated = false;
        callback && callback();
    ,
    function (error) 
        $log.error("Error in login! " + JSON.stringify(error));
        $rootScope.authenticated = false;
        callback && callback();
    );

application.yml 我得到了 Spring Security 的这个配置:

grails:
  plugin:
    springsecurity:
      userLookup:
        userDomainClassName: xxx.LoginUser
      rejectIfNoRule: true
      fii:
        rejectPublicInvocations: false
      controllerAnnotations:
        staticRules:
          [...]

当我调用我的函数并将请求发送到服务器时出现问题。 Spring Security 不接受 mu j_usernamej_password 并且总是返回带有状态 200 和错误文本 "error":"Sorry, we were not able to find a user with that username and password." 的响应

PS 我正在为 Grails (3.0.4) 使用 Spring Security 插件http://grails-plugins.github.io/grails-spring-security-core/guide/index.html

【问题讨论】:

【参考方案1】:

所以这就是问题所在。 Spring Security 插件仅接受带有数据作为查询字符串的POST 请求,当我们通过 Angular 的 $http 调用在 POST 请求中传递一些数据时,它会在请求有效负载正文中发送数据,这会破坏登录,并且您会收到没有用户的消息找到了。

所以第一种方法是使用$httpusernamepassword 作为params 传递:

$http(
    method: 'POST',
    url: '/j_spring_security_check',
    params: j_username: credentials.username, j_password: credentials.password, ajax: true
)

上述方法可以正常工作,但问题是用户名和密码将在查询字符串中发送,因此任何人都可以轻松地在浏览器控制台中读取,因为它不受保护。此外,由于这将作为查询字符串参数传递,因此密码将被记录在各种级别,例如 Tomcat 的 localhost 日志或 nginx 日志。

要解决此问题,请按以下方式更改您的代码:

var data = 'j_username=' + credentials.username + '&j_password=' + credentials.password;

$http(
    method: 'POST',
    url: '@/j_spring_security_check',
    data: data,
    headers: 
        'Content-Type': 'application/x-www-form-urlencoded'
    
)

所以我们在这里所做的是将凭据作为发布数据发送,并以编程方式更改 Content-Type,以便 Angular 可以将其作为发布数据而不是 JSON 发送。

注意:附加建议:Grails request 属性 request.xhr 不会告诉您通过 Angular 发出的请求是 AJAX 请求,因为 Angular 不会发送任何请求标头以使其工作就像 Grails 的 AJAX。所以添加以下代码:

var myApp = angular.module('myApp', []);             // Or whatever your app name is

myApp.run(['$http', function ($http) 
    $http.defaults.headers.common['x-requested-with'] = 'XMLHttpRequest';
]);

现在您不必在 Angular $http 调用中传递 ajax: true

【讨论】:

感谢您提供有关 xhr 属性的说明,我正在对此进行调查。很高兴知道这是预期的行为,我将添加标头,以便让 Grails 区分每种类型的请求 :)

以上是关于如何在 Grails 和 AngularJS 上使用 Spring Security 进行 Ajax 登录的主要内容,如果未能解决你的问题,请参考以下文章

如何将 Angular js 集成到 grails 2.3.4 中?

AngularJS 和 Grails 中基于角色的用户身份验证

Grails、Spring Security 和 Angular JS - 如何保护 URL?

Grails - Ionic - AngularJS - 在这个环境中工作是个好主意吗?

一旦AngularJs中的数据库发生变化,如何实现自动视图更新?

如何使用 Grails Asset 插件引用静态 HTML rsource?