Базовая безопасность в JSF
Я хотел бы видеть простое приложение для входа в систему, но не такое простое, как это.
Я хотел бы достичь понимания того, как работает JSF. Я разработал много ASP.NET, где у вас есть код и вы можете просто проверить, был ли создан сеанс при входе в систему.
Подобное решение в JSF было бы здорово.
Это в основном то, чего я хочу достичь:
- Страница авторизации
- ЕСЛИ ОК
- Создать сеанс и вернуть "успех"
- Если не удалось
- вернуть "провал"
("Успех" и "неудача" сопоставляются с Face-config.xml)
На странице успеха я хочу быть уверен, что пользователь вошел в систему, поэтому не следует переходить к "success.jspx", если вы не получили правильный сеанс.
4 ответа
В ядре JSF нет встроенной функциональности аутентификации, кроме возможности использовать такие вещи, как компонент rendered
атрибуты, направленные на безопасность на основе ролей.
По умолчанию приложение JSF использует те же механизмы безопасности, управляемые контейнером, что и веб-компонент, который его содержит ( учебное пособие по JEE5). Сторонние фреймворки, такие как Seam, могут предоставить альтернативы.
Если вы хотите добавить собственную защиту приложения, фильтр сервлетов является одним из более простых механизмов.
Этот фильтр защищает ресурсы под restricted
каталог, как определено в web.xml
:
<filter>
<filter-name>AuthenticationFilter</filter-name>
<filter-class>restricted.AuthenticationFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthenticationFilter</filter-name>
<url-pattern>/restricted/*</url-pattern>
</filter-mapping>
Реализация класса фильтра:
public class AuthenticationFilter implements Filter {
private FilterConfig config;
public void doFilter(ServletRequest req, ServletResponse resp,
FilterChain chain) throws IOException, ServletException {
if (((HttpServletRequest) req).getSession().getAttribute(
AuthenticationBean.AUTH_KEY) == null) {
((HttpServletResponse) resp).sendRedirect("../restricted_login.faces");
} else {
chain.doFilter(req, resp);
}
}
public void init(FilterConfig config) throws ServletException {
this.config = config;
}
public void destroy() {
config = null;
}
}
Бин входа, определенный в faces-config.xml
:
public class AuthenticationBean {
public static final String AUTH_KEY = "app.user.name";
private String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public boolean isLoggedIn() {
return FacesContext.getCurrentInstance().getExternalContext()
.getSessionMap().get(AUTH_KEY) != null;
}
public String login() {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap().put(
AUTH_KEY, name);
return "secret";
}
public String logout() {
FacesContext.getCurrentInstance().getExternalContext().getSessionMap()
.remove(AUTH_KEY);
return null;
}
}
Форма входа в систему JSF в restricted_login.jsp
страница:
<f:view>
<p><a href="restricted/secret.faces">try to go to secret
page</a></p>
<h:form>
Username:
<h:panelGroup rendered="#{not authenticationBean.loggedIn}">
<h:inputText value="#{authenticationBean.name}" />
<h:commandButton value="login"
action="#{authenticationBean.login}" />
</h:panelGroup>
<h:commandButton value="logout"
action="#{authenticationBean.logout}"
rendered="#{authenticationBean.loggedIn}" />
</h:form>
</f:view>
(URL/ механизм перенаправления был выбран для краткости, а не для какой-либо передовой практики; дополнительные параметры см. В Servlet API.)
Если вы хотите попробовать более продвинутый подход, я предлагаю рассмотреть Spring-Security+JSF. Отлично работает.
Вы можете написать свое приложение, как если бы оно не было защищено, а затем просто настроить, какие области следует защищать, используя аспекты.
Безопасность Spring: http://static.springsource.org/spring-security/site/
Учебное пособие: http://ocpsoft.com/java/acegi-spring-security-jsf-login-page/
Лучший способ сделать это - использовать управляемую контейнером безопасность.
Вот учебник о том, как этого добиться с glassfish
а также jsf
,
Если вы используете шаблоны, я обнаружил, что вам не нужен фильтр.
index.jsp
<jsp:forward page="startup.faces"></jsp:forward>
startup.xhtml (.faces), на самом деле не пытается показать экран, он вызывает javascript startupSubmit() при загрузке и нажимает кнопку. Это отправляет поток прямо в метод start() в StartupBean.java.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
.
.
<script type="text/javascript">
function startupSubmit() {
**document.getElementById('startupForm:startupBtn').click();**
}
</script>
<h:body onload="startupSubmit()">
<h:form id="startupForm">
<p:commandButton id="startupBtn" value="" action="#{startupBean.start}" ajax="false" />
</h:form>
</h:body>
</html>
StartupBean.java (не является частью файла template.xhtml ниже). Метод start() в StartupBean устанавливает переменную с именем authorised в true (по умолчанию false), а затем переходит к first.xhtml. Вы можете использовать любые критерии, которые вы хотите определить, установлено ли для параметра true значение..., например, критерии входа.
package gov.irs.eservices.managementBeans;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
@ManagedBean(name="startupBean")
@SessionScoped
public class StartupBean {
private boolean authorized;
public StartupBean() {
}
public String start() {
**setAuthorized(true);**
return "first";
}
public boolean isAuthorized() {
return authorized;
}
public void setAuthorized(boolean authorized) {
this.authorized = authorized;
}
}
template.xhtml. В template.xhtml, просто внутри формы, вы помещаете ah: или p: panelGrid и отображаете его, только если для startupBean.authorized задано значение true. Единственный способ, которым пользователь может получить доступ к страницам, содержащимся в шаблоне, - это если они сначала проходят через StartupBean.java.
<f:view>
<div id="container">
<h:form id="templateForm">
**<p:panelGrid rendered="#{startupBean.authorized}">**
<div id="header">
<ui:include src="header.xhtml" />
</div>
<div id="wrapper">
<div id="firstId">
<ui:insert name="first"></ui:insert>
</div>
.
. <!-- MORE PAGES -->
.
.
</div>
<div id="footer">
<ui:include src="footer.xhtml" />
</div>
</p:panelGrid>
</h:form>
</div>
</f:view>
Итак, это мое решение. Я проверил это довольно тщательно, и, кажется, работает нормально.