JavaEE - 无法摆脱会话
JavaEE - Cannot get rid of session
我使用 JavaEE、JSF 和一个 Servlet 构建了 Web 应用程序。
我通过 Glassfish 和 web.xml 使用安全性。当我登录时,我可以做任何我被允许做的事情,但一旦我注销,问题就会发生。
我确实注销了,我被重定向到主页,在其他(不安全的)页面中会话不再可见,但是一旦我进入安全页面 - 这里它被命名为 secured.xhtml - 我恢复了我的会话,我可以看到我的信息并再次执行我之前被允许执行的任何操作。
Imo 问题开始于 user data constraint in web.xml and
传输保证 设置为 机密。如果我不设置它,我的信息在其他页面上不可见,但注销仍然不起作用,如果它设置它只是显示在所有页面上,如前所述。
这是我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
id="WebApp_ID" version="3.1"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>IssueTrack</display-name>
<!-- Change to "Production" when you are ready to deploy -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<!-- Welcome page -->
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<!-- JSF mapping -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map these files with JSF -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>issuetrack-realm</realm-name>
</login-config>
<security-role>
<role-name>User</role-name>
</security-role>
<security-role>
<role-name>Admin</role-name>
</security-role>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/index.xhtml</location>
</error-page>
<session-config>
<tracking-mode>COOKIE</tracking-mode>
<cookie-config>
<secure>true</secure>
<http-only>true</http-only>
</cookie-config>
<session-timeout>5</session-timeout>
</session-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Secured pages</web-resource-name>
<description/>
<url-pattern>secured.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>*</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
LogoutServlet(应该)注销已登录的用户。
public class LogoutServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Destroys the session for this user.
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
request.logout();
}
response.sendRedirect("/");
}
}
编辑
context.xml 看起来像这样
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/" />
glassfish-web.xml 看起来像
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="/">
<context-root>/</context-root>
<security-role-mapping>
<role-name>Admin</role-name>
<principal-name>Admin</principal-name>
<group-name>Admin</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>User</role-name>
<principal-name>User</principal-name>
<group-name>User</group-name>
</security-role-mapping>
</glassfish-web-app>
我的豆子都是这样的..
@Named
@RequestScoped
public class IssueBean extends BasicBean {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Inject
private IssueService gServ;
private Issue issue = new Issue();
public List<Issue> getIssues() {
try {
return gServ.viewAll();
} catch (ValidationException ex) {
showException(ex);
return null;
}
}
public Issue getIssueById() {
if (id < 1) {
navigate("/issues.xhtml");
}
try {
issue = gServ.view(id);
} catch (ValidationException ex) {
showException(ex);
}
if (issue == null || issue.getPriority()== null) {
navigate("/issues.xhtml");
}
return issue;
}
public Issue getIssue() {
return issue;
}
public void setIssue(Issue issue) {
this.issue = issue;
}
public String saveIssue() {
try {
gServ.add(issue);
return "/issues.xhtml?faces-redirect=true";
} catch (ValidationException ex) {
showException(ex);
return "";
}
}
public String updateIssue() {
try {
gServ.edit(issue);
return "/issues.xhtml?faces-redirect=true";
} catch (ValidationException ex) {
showException(ex);
return "";
}
}
public void init() {
if (id < 1) {
navigate("/issues.xhtml");
}
try {
issue = gServ.view(id);
} catch (ValidationException ex) {
showException(ex);
}
if (issue == null || issue.getPriority()== null) {
navigate("/issues.xhtml");
}
}
}
Basic Bean 看起来像这样
public class BasicBean {
protected void navigate(String where) {
ConfigurableNavigationHandler nav
= (ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nav.performNavigation(where);
}
protected void showException(Exception ex){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Validation Error - " + ex.getMessage(), ex.toString()));
}
}
我认为您可以使用以前的安全页面,因为您的浏览器正在缓存会话。包括以下内容作为注销的一部分,以便不缓存响应。这也适用于所有浏览器。
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
我猜这是因为您在不需要 cookie、session 标识符和登录页面的应用程序中使用 BASIC auth method,而是使用标准 HTTP headers。这意味着一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次访问该站点时会自动登录。
因此,一种处理方法是实施 Form-Based 身份验证。或者如果你想坚持使用 BASIC - 使用建议 given in this thread.
有关身份验证机制的详细信息,请参阅 Java EE tutorial。
我使用 JavaEE、JSF 和一个 Servlet 构建了 Web 应用程序。
我通过 Glassfish 和 web.xml 使用安全性。当我登录时,我可以做任何我被允许做的事情,但一旦我注销,问题就会发生。
我确实注销了,我被重定向到主页,在其他(不安全的)页面中会话不再可见,但是一旦我进入安全页面 - 这里它被命名为 secured.xhtml - 我恢复了我的会话,我可以看到我的信息并再次执行我之前被允许执行的任何操作。
Imo 问题开始于 user data constraint in web.xml and
传输保证 设置为 机密。如果我不设置它,我的信息在其他页面上不可见,但注销仍然不起作用,如果它设置它只是显示在所有页面上,如前所述。
这是我的web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app
id="WebApp_ID" version="3.1"
xmlns="http://java.sun.com/xml/ns/j2ee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
<display-name>IssueTrack</display-name>
<!-- Change to "Production" when you are ready to deploy -->
<context-param>
<param-name>javax.faces.PROJECT_STAGE</param-name>
<param-value>Development</param-value>
</context-param>
<!-- Welcome page -->
<welcome-file-list>
<welcome-file>index.xhtml</welcome-file>
</welcome-file-list>
<!-- JSF mapping -->
<servlet>
<servlet-name>Faces Servlet</servlet-name>
<servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<!-- Map these files with JSF -->
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>/faces/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.jsf</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.faces</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>Faces Servlet</servlet-name>
<url-pattern>*.xhtml</url-pattern>
</servlet-mapping>
<login-config>
<auth-method>BASIC</auth-method>
<realm-name>issuetrack-realm</realm-name>
</login-config>
<security-role>
<role-name>User</role-name>
</security-role>
<security-role>
<role-name>Admin</role-name>
</security-role>
<error-page>
<exception-type>javax.faces.application.ViewExpiredException</exception-type>
<location>/index.xhtml</location>
</error-page>
<session-config>
<tracking-mode>COOKIE</tracking-mode>
<cookie-config>
<secure>true</secure>
<http-only>true</http-only>
</cookie-config>
<session-timeout>5</session-timeout>
</session-config>
<security-constraint>
<web-resource-collection>
<web-resource-name>Secured pages</web-resource-name>
<description/>
<url-pattern>secured.xhtml</url-pattern>
</web-resource-collection>
<auth-constraint>
<description/>
<role-name>*</role-name>
</auth-constraint>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>
</web-app>
LogoutServlet(应该)注销已登录的用户。
public class LogoutServlet extends HttpServlet {
@Override
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// Destroys the session for this user.
HttpSession session = request.getSession(false);
if (session != null) {
session.invalidate();
request.logout();
}
response.sendRedirect("/");
}
}
编辑
context.xml 看起来像这样
<?xml version="1.0" encoding="UTF-8"?>
<Context antiJARLocking="true" path="/" />
glassfish-web.xml 看起来像
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE glassfish-web-app PUBLIC
"-//GlassFish.org//DTD GlassFish Application Server 3.1 Servlet 3.0//EN"
"http://glassfish.org/dtds/glassfish-web-app_3_0-1.dtd">
<glassfish-web-app error-url="/">
<context-root>/</context-root>
<security-role-mapping>
<role-name>Admin</role-name>
<principal-name>Admin</principal-name>
<group-name>Admin</group-name>
</security-role-mapping>
<security-role-mapping>
<role-name>User</role-name>
<principal-name>User</principal-name>
<group-name>User</group-name>
</security-role-mapping>
</glassfish-web-app>
我的豆子都是这样的..
@Named
@RequestScoped
public class IssueBean extends BasicBean {
private long id;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
@Inject
private IssueService gServ;
private Issue issue = new Issue();
public List<Issue> getIssues() {
try {
return gServ.viewAll();
} catch (ValidationException ex) {
showException(ex);
return null;
}
}
public Issue getIssueById() {
if (id < 1) {
navigate("/issues.xhtml");
}
try {
issue = gServ.view(id);
} catch (ValidationException ex) {
showException(ex);
}
if (issue == null || issue.getPriority()== null) {
navigate("/issues.xhtml");
}
return issue;
}
public Issue getIssue() {
return issue;
}
public void setIssue(Issue issue) {
this.issue = issue;
}
public String saveIssue() {
try {
gServ.add(issue);
return "/issues.xhtml?faces-redirect=true";
} catch (ValidationException ex) {
showException(ex);
return "";
}
}
public String updateIssue() {
try {
gServ.edit(issue);
return "/issues.xhtml?faces-redirect=true";
} catch (ValidationException ex) {
showException(ex);
return "";
}
}
public void init() {
if (id < 1) {
navigate("/issues.xhtml");
}
try {
issue = gServ.view(id);
} catch (ValidationException ex) {
showException(ex);
}
if (issue == null || issue.getPriority()== null) {
navigate("/issues.xhtml");
}
}
}
Basic Bean 看起来像这样
public class BasicBean {
protected void navigate(String where) {
ConfigurableNavigationHandler nav
= (ConfigurableNavigationHandler) FacesContext.getCurrentInstance().getApplication().getNavigationHandler();
nav.performNavigation(where);
}
protected void showException(Exception ex){
FacesContext.getCurrentInstance().addMessage(null, new FacesMessage("Validation Error - " + ex.getMessage(), ex.toString()));
}
}
我认为您可以使用以前的安全页面,因为您的浏览器正在缓存会话。包括以下内容作为注销的一部分,以便不缓存响应。这也适用于所有浏览器。
response.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
response.setHeader("Pragma", "no-cache");
response.setDateHeader("Expires", 0);
我猜这是因为您在不需要 cookie、session 标识符和登录页面的应用程序中使用 BASIC auth method,而是使用标准 HTTP headers。这意味着一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次访问该站点时会自动登录。
因此,一种处理方法是实施 Form-Based 身份验证。或者如果你想坚持使用 BASIC - 使用建议 given in this thread.
有关身份验证机制的详细信息,请参阅 Java EE tutorial。