REST应用程序中的基本身份validation

环境:

  • JAVA
  • Glassfish的
  • 不同机器中的REST服务
  • 带有AJAX和JQuery的HTML5客户端
  • 新泽西

这是我到目前为止所实现的:

HTML5客户端###

$('#btnSignIn').click(function () { var username = $("#username").val(); var password = $("#password").val(); function make_base_auth(user, password) { var tok = user + ':' + password; var final = "Basic " + $.base64.encode(tok); console.log("FINAL---->" + final); alert("FINAL---->" + final); return final; } $.ajax({ type: "GET", contentType: "application/json", url: "http://localhost:8080/SesameService/webresources/users/secured/login", crossDomain: true, dataType: "text", async: false, data: {}, beforeSend: function (xhr) { xhr.setRequestHeader('authorization', make_base_auth(username, password)); }, success: function () { alert('Thanks for your signin in! '); }, error: function (jqXHR, textStatus, errorThrown) { console.log(textStatus, errorThrown); alert(' Error in signIn-process!! ' + textStatus); } }); }); 

服务器

在安全性方面,我没有启用安全管理器,它被禁用!

我已经为Glassfish配置了BASIC身份validation,我的web.xml看起来像这样:

  ServletAdaptor /webresources/*    REST Protected resources  /users/*   admin customer user    BASIC jdbcRealm   admin   user    customer  

GLASSFISH

在此处输入图像描述

LOG

 FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/webresources/users/secured/login" "GET") FINE: [Web-Security] hasUserDataPermission isGranted: true FINE: [Web-Security] Policy Context ID was: SesameService/SesameService FINE: [Web-Security] hasResource isGranted: true FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/webresources/users/secured/login" "GET") 

题:

  1. 如果我在用户注册并在SSL / HTTPS下传输时在客户端加密(NOT编码)密码,这种安全且好的方法是否实现?

  2. 如果我在没有客户端的情况下使用REST服务,它总是打开的,为什么? 没有BASIC认证? 我是否理解了这些url模式的错误?

     http://localhost:8080/SesameService/webresources/users/secured/login 
  3. 如果我得到这个如何测试,因为现在如果我认证一次,我总是被授权? 是否可以在REST服务中以编程方式“注销”,或者通常如何实现注销?

  4. 在标题中使用强制base64编码的用户名:password时,我是否必须将我的用户名和密码编码为DB? 我尝试了,并将编码(允许值为Hex和Base64)添加到jdbcRealm到Glassfish,似乎密码就足够了,但是当两者都在客户端编码时会发生什么?

更新:我更改了web.xml,现在BASIC-authentication在浏览器中直接调用REST服务时正在运行: http://localhost:8080/SesameService/users/secured/login

变化:

  • 我在Glassfish中启用了安全管理器
  • 我改变了url-pattern

    ServletAdaptor / * —->我关闭了webresources。 它是由Netbeans生成的

  • 我将url更改为服务: http://localhost:8080/SesameService/users/secured/login

现在,当我尝试从HTML5客户端进行身份validation时,我获得了HTTP / 1.1 401 Unauthorized。

请求标题: `

 Origin: http://localhost:8383 Host:`localhost:8080` Connection:keep-alive Access-Control-Request-Method:GET Access-Control-Request-Headers:authorization,content-type` 

响应:

 x-powered-by:Servlet/3.0 JSP/2.2 (GlassFish Server Open Source Edition 3.1.2.2 Java/Oracle Corporation/1.7) WWW-Authenticate:Basic realm="jdbcRealm" Server:GlassFish Server Open Source Edition 3.1.2.2 Pragma:No-cache Expires:Thu, 01 Jan 1970 02:00:00 EET Date:Sat, 13 Apr 2013 15:25:06 GMT Content-Type:text/html Content-Length:1073 Cache-Control:no-cache 

更新2

当我尝试使用JavaScript + Authorization-header进行身份validation时,我收到了401错误,并且在日志中:

 FINE: [Web-Security] Setting Policy Context ID: old = null ctxID = SesameService/SesameService FINE: [Web-Security] hasUserDataPermission perm: ("javax.security.jacc.WebUserDataPermission" "/users/secured/login" "OPTIONS") FINE: [Web-Security] hasUserDataPermission isGranted: true---->!!!!!!!!!!!!! FINE: [Web-Security] Policy Context ID was: SesameService/SesameService FINE: [Web-Security] Codesource with Web URL: file:/SesameService/SesameService FINE: [Web-Security] Checking Web Permission with Principals : null------->!!!!!!! FINE: [Web-Security] Web Permission = ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS") FINEST: JACC Policy Provider: PolicyWrapper.implies, context (SesameService/SesameService)- result was(false) permission (("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS")) FINE: [Web-Security] hasResource isGranted: false------->!!!!!!!!! FINE: [Web-Security] hasResource perm: ("javax.security.jacc.WebResourcePermission" "/users/secured/login" "OPTIONS") FINEST: JACC Policy Provider: PolicyWrapper.getPermissions(cs), context (null) codesource ((null )) permissions: java.security.Permissions@5d4de3b0 ( 

****更新3 ****我不能成为第一个也是唯一一个试图在跨域案例中使用BASIC进行身份validation的人。 我更改了我的交叉源filter:response.getHttpHeaders()。putSingle(“Access-Control-Allow-Headers”,“Authorization”);

没有401错误,但JavaScript仍然出错。 在Glassfish日志中:

 FINEST: JACC Policy Provider: getPolicy (SesameService/SesameService) is NOT in service----->!!!!!!!! FINE: JACC Policy Provider: file arrival check type: granted arrived: false exists: false lastModified: 0 storedTime: 1365968416000 state: deleted SesameService/SesameService FINE: JACC Policy Provider: file arrival check type: excluded arrived: false exists: false lastModified: 0 storedTime: 0 state: deleted SesameService/SesameService FINE: TM: getTransaction: tx=null, tm=null FINE: TM: componentDestroyedorg.apache.catalina.servlets.DefaultServlet@227fe9a8 FINE: TM: resourceTable before: 0 FINE: TM: resourceTable after: 0 

顺便说一句,因为我从来没有得到这项工作,这比在自己的域中直接调用REST服务一样。 那么,第一个客户端请求,服务器请求和用户名密码窗口打开,然后客户端请求和服务器validation并响应页面? 我试图得到它:请求具有授权标头,来自服务器的响应与来自其余服务的结果,就是这样。 知道如何保护REST服务吗? 比那更容易? 这是不可能的。

更新4

我只是试图将我的HTML5客户端移动到java web-project下,只是纯html页面并且在同一个域下,BASIC-authentication正在100%工作。 所以原因是因为跨域环境。

如果我在用户注册并在SSL / HTTPS下传输时在客户端加密(NOT编码)密码,这种安全且好的方法是否实现?

最有可能的是,您应该通过SSL / HTTPS以纯文本forms传递密码。

SSL / HTTPS中的所有通信都是加密的,因此加密密码可能不是一个好主意,除非您需要确保Web服务器(技术上是HTTPS终结器)无法看到密码。

如果我在没有客户端的情况下使用REST服务,它总是打开的,为什么? 没有BASIC认证? 我是否理解了这些url模式的错误?

我不确定我理解这个问题。 但是,BASIC auth不是REST中用于身份validation的良好模式,因为它以纯文本forms传递密码。

如果我得到这个如何测试,因为现在如果我认证一次,我总是被授权? 是否可以在REST服务中以编程方式“注销”,或者通常如何实现注销?

在Basic Auth中,客户端在每个HTTP请求中传递用户名和密码。 如果客户端未传递凭据,则服务器拒绝该请求。 因此,没有会话的概念。

但是,就Java EE服务器而言,登录会创建用户会话,同一用户的未来请求将使用相同的会话。 如果您这样配置它,此会话将超时。

如果注销很重要(即控制用户会话),则必须为此创建一个servlet(/ logout),这会使HTTP会话无效。

标准Java安全模型的工作原理如下:当用户登录到安全领域时,Java EE服务器会在浏览器中存储安全cookie。 浏览器在每个请求中将此cookie发送回Java EE服务器到同一个域。 Java EE服务器在每个请求中检查此cookie,并使用它来标识用户,将请求连接到用户的会话。

因此,您可能希望在与Web应用程序相同的安全领域中使用REST服务,因此浏览器和服务器可以无缝地工作。

在标题中使用强制base64编码的用户名:password时,我是否必须将我的用户名和密码编码为DB? 我尝试了,并将编码(允许值为Hex和Base64)添加到jdbcRealm到Glassfish,似乎密码就足够了,但是当两者都在客户端编码时会发生什么?

不,不要对用户名或密码进行编码 – 这一切都在浏览器和Glassfish深处处理。 如果您在客户端编码,客户端将编码编码,服务器将拒绝密码。


你能不能告诉我是否可以使用jtml中的j_security_check与javaScript或我再次遇到问题:)我已经制作了几个Primefaces + jsf-application,其中我使用了FORM-auth并且没有任何问题,但是这对我来说完全是灾难。

假设RESTful服务保留在同一个域和安全领域(然后登录到Web应用程序将允许浏览器将正确的cookie发送到REST URI),您应该能够使用j_security_check轻松地使用j_security_check。

但请注意,其他应用程序将无法访问REST服务。 基本上,他们必须通过j_security_check登录,然后维护Glassfish发送的cookie。 如果您确实需要其他应用程序以编程方式访问这些服务,那么您将需要另一个解决方案:

  1. 您可以设置安全域以允许不同的身份validation器“足够”; 设置HTTP BASIC Auth并确保没有标记为“必要”
  2. 两次部署RESTful服务,另一种是不同的URI。 如果要使用HTTP BASIC Auth,这可能是SSL / HTTPS端点,以确保安全地处理密码

我正在使用Spring安全性的Spring MVC框架并使用基本身份validation:

基本上,在HTTP基本身份validation中,在Base64类(来自util包)的帮助下,用户名和密码将转换为密钥或访问令牌。

并将该密钥设置到HTTP URL的标头中,然后命中到服务器。

它工作正常并在服务器上:用同一个Base64解码用户名密码密钥,然后匹配数据库用户名和密码。 如果认证完成则进一步处理。

这样可以提供API Urls的安全性。 每个人都不容易进入。

代码:创建访问令牌(密钥)代码是:

注意:我们在Base64中传递字符串(来自util包)“YourUsername:YourPassword”进行编码。
是的,用户名和密码是“:”分开。

  String encodeddata = new String(Base64.encodeBase64("username:password".getBytes())); System.out.println("encodedBytes " + encodeddata); 

将密钥设置为标头的代码:

//请求使用KEY的URL

  HttpClient client = HttpClientBuilder.create().build(); HttpGet get = new HttpGet("http://google.com/Abc/api/vou/redeemed"); get.setHeader("Authorization", "Basic "+encodeddata); //key getting above 

注意:您可以将此与Get和Post方法一起使用。 这里我只使用get方法。 //响应

  HttpResponse jresponse = client.execute(get); System.out.println("Response Code : "+ jresponse.getStatusLine().getStatusCode()); BufferedReader rd = new BufferedReader(new InputStreamReader(jresponse.getEntity().getContent())); StringBuffer result = new StringBuffer(); String line = ""; while ((line = rd.readLine()) != null) { result.append(line); } System.out.println("------Response is ::: "+ result); 

// DECODE键

  String usernameAndPassword = null; try { usernameAndPassword = new String(Base64.getDecoder().decode(encodedUserPassword)); } catch (Exception e) { System.out.println("SERVER_ERROR"); } System.out.println(usernameAndPassword); final StringTokenizer tokenizer = new StringTokenizer(encodedUserPassword, ":"); final String username = tokenizer.nextToken(); final String password = tokenizer.nextToken(); System.out.println(username); System.out.println(password);