2013-08-18 42 views
14

Tôi đang xây dựng một ứng dụng web AngularJS sử dụng API RESTful (Jersey).Cách xác thực đúng máy khách AngularJS với máy chủ

Ở phía máy chủ, tôi đang sử dụng Máy chủ ứng dụng Java (chi tiết Glassfish 4).

thiết lập của tôi là như sau:

  • AngularJS webapp được triển khai như một tập tin chiến tranh duy nhất để các máy chủ ứng dụng Java EE.
  • RESTfulAPI (và logic phụ trợ) cũng được triển khai dưới dạng tệp chiến tranh cho cùng một máy chủ ứng dụng Java EE.
  • Ứng dụng web AngularJS gọi API REST để nhận dữ liệu cần thiết.
  • API RESTful:
    • /api/public/* để truy cập công khai không hạn chế (ví dụ:/api/public/users/signup để đăng ký làm người dùng mới). Bất kỳ người dùng nào đều được phép truy cập khu vực này. Không yêu cầu đăng nhập
    • /api/private/* để truy cập hạn chế (ví dụ/api/private/tài khoản/{id} để lấy một số tài khoản dữ liệu cụ thể)
  • Các nguồn tin được bảo vệ với các khái niệm an ninh nội bộ Java EE (xem dưới đây cho chi tiết web.xml).

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> 

Thiết lập này làm việc cho tôi, nhưng chỉ khi tôi gọi các URL bằng tay trong trình duyệt. Nếu tôi không được xác thực và giải quyết một khu vực được bảo mật, trình duyệt sẽ yêu cầu tên người dùng và mật khẩu. Nếu thông tin đăng nhập được cung cấp hợp lệ, tôi từ đó có quyền truy cập vào khu vực bị hạn chế: Tốt.

Nhưng làm cách nào để làm việc đó với AngularJS? Để đăng nhập, có một cuộc gọi POST API: /api/public/users/login nơi bạn phải cung cấp bằng chứng xác thực từ biểu mẫu (tên người dùng và mật khẩu).

Mã phía khách hàng là: Mã phía

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()); 
     }); 
    }; 
}); 

Khách hàng dường như làm việc. Tôi cũng có một số tuyến đường để đảm bảo nội dung ở phía khách hàng, v.v. Có một số bài viết ở đó mô tả chi tiết mã phía máy khách. Vì vậy, "đoạn mã" này là đủ.

Các mã phía máy chủ là:

@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(); 
    } 
} 

Nhưng tuy nhiên, điều này không "xác thực" các mặt hàng khác cho các yêu cầu tiếp theo. Khi tôi thực hiện cuộc gọi API trên một khu vực hạn chế sau khi đăng nhập thành công, tôi nhận được phản hồi 403 FORBIDDEN từ phía máy chủ. Vì vậy, tôi cho rằng tôi đang làm điều gì sai. Bạn có bất kỳ ý tưởng làm thế nào để xác thực khách hàng đến máy chủ cho các yêu cầu thêm?

Một giải pháp có thể là chuyển sang xác thực dựa trên MẪU và chỉ cần gọi j_security_check với j_username và j_password, nhưng bây giờ tôi muốn gắn với BASIC-Authentication và thực hiện xác thực theo cách thủ công qua RESTful API.

Cài đặt $httpProvider.defaults.withCredentials = true; bằng cách nào đó dường như không có bất kỳ ảnh hưởng nào.

Cập nhật:

Nhờ chóp lossleader tôi đã giải quyết được vấn đề. Tôi đã xóa phương thức login(), vì tôi muốn Java EE-Server quản lý xác thực.

Để truy cập các khu vực được bảo mật, ứng dụng web AngularJS phải đặt HTTP-Header chính xác. Trong trường hợp của tôi $http.defaults.headers.common['Authorization'] = 'Basic <username:pw>'; trong đó username:password phải được mã hóa Base64.

Sau khi tôi đặt tiêu đề chính xác, không có Dấu nhắc mật khẩu được hiển thị và ứng dụng web AngularJS có thể truy cập REST API.

+1

Tôi không thấy cách request.login() sẽ dẫn đến khách hàng nhận được tiêu đề http auth (thực sự chỉ 200 của bạn quay lại phải không?) Trong khi request.authenticate() khá rõ ràng hoạt động với phản hồi và có thể do đó đặt tiêu đề. Tôi hoặc là sẽ sử dụng xác thực và để cho trình duyệt làm công việc của mình hoặc sử dụng các hình thức. Nếu bạn thực sự muốn một cái gì đó ở giữa, tôi nghĩ bạn nên xem phản hồi và xem liệu bất kỳ tiêu đề nào thậm chí có được thiết lập hay không. – lossleader

+1

Hey lossleader, cảm ơn bạn đã trả lời. Tất nhiên bạn đúng, tôi không đặt tiêu đề đúng và tất nhiên đó là vấn đề của tôi. Sau gợi ý của bạn, tôi đã xác thực để làm việc với xác thực dựa trên BASIC và FORM. – zip

Trả lời

5

Nhờ mẹo của người giảm giá tôi đã giải quyết được sự cố. Tôi đã xóa phương thức login(), bởi vì tôi muốn Java EE-Server quản lý xác thực.

Để truy cập các khu vực được bảo mật, ứng dụng web AngularJS phải đặt HTTP-Header chính xác. Trong trường hợp của tôi $ http.defaults.headers.common ['Authorization'] = 'Basic'; trong đó tên người dùng: mật khẩu phải được mã hóa Base64.

Sau khi tôi đặt tiêu đề chính xác, không có Dấu nhắc mật khẩu được hiển thị và ứng dụng web AngularJS có thể truy cập REST API.

+1

Xin chào, tôi đã hỏi một câu hỏi tương tự như trong: http://stackoverflow.com/questions/24129848/how-to-integrate-angularjs-and-java-jaas-based-authentication - bạn có thực sự đang sử dụng Trang đăng nhập không mẫu cho cơ chế đăng nhập? Bạn có thể đăng đoạn mã nơi bạn thực sự đăng nhập và cho các cuộc gọi tiếp theo tới API bạn điền vào tiêu đề bằng mã hóa Base 64 không? Tôi đang sử dụng tài nguyên AngularJS cho API Restful cũng sẽ hoạt động với cách tiếp cận của bạn? Cảm ơn. – guilhebl

Các vấn đề liên quan