Java getUserPrincipal返回null
我使用AngularJS作为前端,使用JavaEE作为后端。 我使用RESTful服务创建了两种登录和注销方法:Java getUserPrincipal返回null,java,angularjs,Java,Angularjs,我使用AngularJS作为前端,使用JavaEE作为后端。 我使用RESTful服务创建了两种登录和注销方法: @POST @Path("login") @Produces("application/json") public Response login(@Context HttpServletRequest req, UserTable user) { if (req.getUserPrincipal() == null) { try { r
@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。我做错了什么?RESTful服务意味着无状态。需要授权和身份验证的请求会在每个请求上发送身份验证令牌,然后由服务器验证。这背后的想法是,给定一个令牌,您可以从任何客户端(桌面、电话)请求获取资源。这对于第三方集成来说非常方便,如果您的应用程序要支持负载平衡器,这是必须的 这篇文章对于理解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会话
您可以通过调用HttpServletRequest.getSession()
方法来实现这一点,如下所示:
req.getSession(true); // Creates a new HTTP Session BEFORE the login.
req.login(user.getUsername(), user.getPassword());
确保服务器在响应中返回JSESSIONID cookie。之后,浏览器将处理它并将其发送到服务器,而您无需担心它或自己处理它
来自登录的响应
请求进一步呼叫(服务呼叫、检查登录、注销等)
更新
也许你需要告诉AngularJS把饼干送来。就我刚才读到的内容而言,默认设置似乎不是发送cookies
试试这个帖子
更新2
跨域策略可能是一个难题,但它们必须存在,才能确保对web内容的访问安全。Java服务器运行正常,正在进行身份验证,并且正在共享cookie。Java服务器从一开始就很好
当涉及到跨域时,任何中间件技术的问题都是一样的
浏览器正在阻止您的应用程序,因为不允许您的客户端域(运行JavaScript的地方)访问Java服务器域。应用程序(AngularJS和Java服务器)在不同的域中执行,因此浏览器会阻止“隐藏”的JavaScript调用。旧的IE版本在过去允许它
例如:
- JavaScript代码从本地主机或本地文件系统加载
- Java服务器正在运行(将此替换为您的IP或任何地址)
也许可以救你:
JSONP允许页面通过以下方式接收来自不同域的JSON数据:
在页面中添加一个元素,加载带有
来自不同域的回调
跨域策略将为这两个应用程序验证:协议、主机名和端口。如果其中一个不同,则会发生安全性,程序会失败
更多信息请点击此处:
你的AngularJS也没有问题。我在过去遇到过这种情况,您可以使用纯Java脚本复制它(这是可以适应您的问题的功能代码):
浏览器控制台中将显示以下错误:
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与Java服务器进行通信,设置如下(.header(“Access Control allow Origin”,“*”)
)的访问控制允许原点:
警告:为运行应用程序客户端的域替换“*”
我建议您调查跨域策略主题。如果可以,也许一个简单的解决方案是在Java容器中运行客户端JavaScript。然后两个应用程序将自动位于同一个域中
我的意思是,如果使用JSP/Servlet发布应用程序客户机Java脚本,就不会有这个问题。如果您是在普通文件中开发JavaScript,只需将它们包装到JavaWeb应用程序中即可。由于您将执行从“xyz.com”域检索的Java脚本代码,因此浏览器将允许在同一“xyz.com”中运行的Java代码交换信息。这会奏效的
很抱歉,我花了太多时间才意识到您正在对另一个域进行AJAX调用
如果您需要与不同的域进行通信(可能服务器是一个外部服务),但找不到任何帮助,我建议您针对跨域问题专门提出另一个问题。据我所知,这个问题已不再与Java服务器本身有关。听起来问题似乎在您的服务器端。设置一些断点以查看所采用的路径,并沿途检查数据。如果您在注销后再次尝试登录,getUserPrincipal将始终为null,因为用户未经过身份验证。这就是方法req.logout()所做的。@rahpuser我尝试过使用login方法,但没有注销,我第二次使用了它,但是第二次,getUserPrincipal()等于null。Cookie是否在交互过程中保留?@SoluableNonagon我已经这样做了。我试着写这样的东西:Principal p=req.getUserPrincipal();在登录和注销方法中。每次“p”等于null时,服务器都已成功返回JSESSIONID(如第一个屏幕截图中所示)。然而,当我调用logout时,getUserPrincipal()仍然有nullvalue@YanIvanEvdokimov在登录中收到JSSessionID cookie后,是否在注销请求中发送了它?不幸的是,没有。它看起来像在您的屏幕截图中,但没有cookietab@YanIvanEvdokimov检查我的更新。我正在考试
return Response.status(Response.Status.OK).header("Access-Control-Allow-Origin", "*").type("text/plain").entity("Login successfull").build();