我正在建立一个使用RESTful API(Jersey)的AngularJS网络应用程序。
在服务器端,我正在使用Java应用程序服务器(详细来说是Glassfish 4)。
我的设置如下:
/api/public/*
/api/private/*
Web.xml
<security-constraint> <web-resource-collection> <web-resource-name>PRIVATE REST API</web-resource-name> <url-pattern>/private/*</url-pattern> <http-method>GET</http-method> <http-method>POST</http-method> <http-method>HEAD</http-method> <http-method>PUT</http-method> <http-method>OPTIONS</http-method> <http-method>TRACE</http-method> <http-method>DELETE</http-method> </web-resource-collection> <auth-constraint> <description>Have to be a USER</description> <role-name>USERS</role-name> </auth-constraint> </security-constraint> <login-config> <auth-method>BASIC</auth-method> <realm-name>userauth</realm-name> </login-config> <security-role> <description/> <role-name>USERS</role-name> </security-role>
此设置对我有用,但前提是我必须在浏览器中手动调用URL。如果我没有通过身份验证并访问安全区域,浏览器会要求输入用户名和密码。如果提供的凭据有效,那么我将可以访问限制区域:很好。
但是如何在AngularJS中使用它呢?要登录,需要进行POST API调用:/api/public/users/login您必须从表单(用户名和密码)中提供凭据。
/api/public/users/login
客户端代码是:
ctrls.controller('LoginController', function($scope, $http, $log, $location, UserService, RemoteServerHelperService) { $scope.loginDataWrong = undefined; $scope.login = function(credentials) { $http.post(RemoteServerHelperService.buildURL('/public/users/login'), credentials) .success(function (data, status) { UserService.setLoggedIn(credentials.email); $scope.loginDataWrong = undefined; $location.path('/app'); $log.info("login attempt: successfull. User.loggedIn:" + UserService.isLoggedIn()); }).error(function (data, status, headers, config) { UserService.invalidate(); $scope.loginDataWrong = true; $log.info("login attempt: failed. User.loggedIn:" + UserService.isLoggedIn()); }); }; });
客户端代码似乎起作用。我也有一些路由可以确保客户端内容的安全,等等。有几篇文章详细描述了客户端代码。因此,此“摘要”应该足够了。
服务器端代码为:
@POST @Path("/login") @Consumes(MediaType.APPLICATION_JSON) public Response login(Credentials credentials, @Context HttpServletRequest request) { if (isAlreadyAuthenticated(request)) { try { request.logout(); } catch (ServletException ex) { return Response.status(Status.CONFLICT).build(); } } // not authenticated try { request.login(credentials.getEmail(), credentials.getPassword()); return Response.ok().build(); } catch (ServletException ex) { return Response.status(Status.CONFLICT).build(); } }
但是,这不会“验证”客户端的进一步请求。成功登录后在受限区域内进行API调用时,我会403 FORBIDDEN从服务器端收到响应。所以我认为我做错了。您有任何想法如何验证客户端到服务器的进一步请求吗?
403 FORBIDDEN
可能的解决方案是切换到基于FORM的身份验证,并简单地使用j_username和j_password调用j_security_check,但是现在我想坚持使用BASIC- Authentication并通过RESTful API手动执行身份验证。
该设置$httpProvider.defaults.withCredentials = true;似乎没有任何效果。
$httpProvider.defaults.withCredentials = true;
更新:
多亏了leaderleader,我才解决了这个问题。我删除了该login()方法,因为我希望Java EE-Server负责身份验证。
login()
要访问安全区域,AngularJS网络应用必须正确设置HTTP标头。在我的情况下$http.defaults.headers.common['Authorization'] = 'Basic <username:pw>';,username:password必须使用Base64编码。
$http.defaults.headers.common['Authorization'] = 'Basic <username:pw>';
username:password
正确设置标题后,将不会显示密码提示,并且AngularJS Web应用程序可以访问REST API。
多亏了leaderleader,我才解决了这个问题。我删除了login()方法,因为我希望Java EE-Server负责身份验证。
要访问安全区域,AngularJS网络应用必须正确设置HTTP标头。就我而言,$ http.defaults.headers.common [‘Authorization’] =’Basic’; 其中username:password必须为Base64编码。