我使用AngularJS作为前端,使用Java EE作为后端。 我使用RESTful服务创建了两种登录和注销方法:
@POST
@Path("login")
@Produces("application/json")
public Response login(@Context HttpServletRequest req, UserTable user) {
if (req.getUserPrincipal() == null) {
try {
req.login(user.getUsername(), user.getPassword());
} catch (ServletException e) {
return Response.status(Response.Status.BAD_REQUEST).type("text/plain").entity("Login or Password is incorrect").build();
}
} else {
return Response.status(Response.Status.OK).type("text/plain").entity("You are already logged in").build();
}
return Response.status(Response.Status.OK).type("text/plain").entity("Login successfull").build();
}
@GET
@Path("logout")
@Produces("application/json")
public Response logout(@Context HttpServletRequest req) {
try {
req.logout();
req.getSession().invalidate();
} catch (ServletException e) {
return Response.status(Response.Status.BAD_REQUEST).type("text/plain").entity("Can not logout").build();
}
return Response.status(Response.Status.OK).type("text/plain").entity("Logout successfull").build();
}
在前端,我使用以下方法:
$http.post(apiUrl + 'usertable/login', {
username: 'admin',
password: 'admin'
});
$http.get(apiUrl + 'usertable/logout').success(function (a) {
var o = a;
});
我可以成功登录:
FINEST: JDBC login succeeded for: admin groups:[Admin]
FINE: JAAS login complete.
FINE: JAAS authentication committed.
FINE: Password login succeeded for : admin
但是当我尝试注销或再次登录时,getUserPrincipal()返回null。我做错了什么?
答案 0 :(得分:2)
在之前手动创建HTTP会话,然后调用login
方法。
您可以通过调用HttpServletRequest.getSession()
方法执行此操作,如下所示:
req.getSession(true); // Creates a new HTTP Session BEFORE the login.
req.login(user.getUsername(), user.getPassword());
确保服务器在响应中返回JSESSIONID cookie。之后,浏览器将处理它并将其发送到服务器,而无需您担心或自行处理。
登录回复
请求进一步通话(服务电话,检查登录,退出等)
也许你需要告诉AngularJS发送Cookies。对于我刚才读到的内容,似乎默认情况下不会发送cookie。
试试这篇文章$http doesn't send cookie in Requests
跨域策略可能很麻烦,但它们需要存在才能保护对Web内容的访问。 Java服务器正常运行,正在进行身份验证并正在共享cookie。从一开始,Java服务器一切都很好。
任何中间件技术遇到跨域问题都是一样的。
浏览器阻止了您的应用程序,因为您的客户端域(运行JavaScript的地方)不允许访问Java服务器域。应用程序(您的AngularJS和Java Server)正在不同的域中执行,因此JavaScript调用"在引擎盖下#34;被浏览器阻止。旧的IE版本过去曾经允许使用它。
示例:
也许JSONP可以救你:
JSONP允许页面通过以下方式接收来自不同域的JSON数据 在页面中添加一个元素,用于加载JSON响应 来自不同域的回调。
对于这两个应用程序,跨域策略将验证:协议,主机名和端口。如果一个不同,则会发生安全性并且程序失败。
此处有更多信息:Same-origin policy
你的AngularJS也没什么问题。我过去遇到过这种情况,您可以使用普通的Java Script复制它(这是可以适应您问题的功能代码):
function loadXMLDoc() {
var xmlhttp=new XMLHttpRequest();
xmlhttp.onreadystatechange=function() {
if (xmlhttp.readyState==4 && xmlhttp.status==200) {
document.getElementById("myDiv").innerHTML=xmlhttp.responseText;
}
}
xmlhttp.open("POST","http://192.168.9.117:8080/restful-login-web/rest/loginservice/login",true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("username=evandro&password=senha123");
}
以下错误将显示在您的浏览器控制台中:
XMLHttpRequest cannot load http://192.168.9.117:8080/restful-login-web/rest/loginservice/login. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'null' is therefore not allowed access.
GET调用也会发生这种情况。
您可以允许外部应用程序使用JavaScript与设置Access-Control-Allow-Origin
的Java服务器进行通信(.header("Access-Control-Allow-Origin", "*")
):
return Response.status(Response.Status.OK).header("Access-Control-Allow-Origin", "*").type("text/plain").entity("Login successfull").build();
警告:替换" *"对于运行应用程序客户端的域。
我建议您调查跨域政策主题。如果可以,也许一个简单的解决方案是在Java容器中运行客户端JavaScript。然后两个应用程序将自动在同一个域中。
我的意思是,如果您使用JSP / Servlet发布应用程序客户端Java脚本,那么您就不会遇到此问题。如果您在普通文件中开发JavaScript,只需将它们包装在Java Web应用程序中即可。因为您将执行从" xyz.com"中检索到的Java脚本代码。域,运行在同一个" xyz.com"将允许浏览器交换信息。这将有效。
对不起,我花了更多的时间才意识到你正在对另一个域进行AJAX调用。
如果您需要沟通不同的域(可能服务器是外部服务)并且您无法找到任何帮助,我建议您专门针对跨域问题打开另一个问题。据我所知,这个问题不再与Java服务器本身相关联。
答案 1 :(得分:1)
RESTful服务意味着无状态。需要授权和身份验证的请求会在每个请求上发送身份验证令牌,然后由服务器进行验证。这背后的想法是,给定令牌,您可以从任何客户端(桌面,电话)发出请求以获取资源。这对于第三方集成非常方便,如果您的应用程序将落后于负载平衡器,则必须使用。
这一特定的阅读对于理解有关RESTful服务的一些概念非常有用:
Do sessions really violate RESTfulness?
使用会话时,必须绑定到单个服务器。通过查看您的问题并阅读更多评论,应用程序似乎正在失去与用户连接的会话。