سؤال

أنا أتساءل ما هو النهج الحالي فيما يتعلق بمصادقة المستخدم لاستخدام تطبيق ويب لاستخدام JSF 2.0 (وإذا كان أي مكونات موجودة) وآليات Java EE 6 الأساسية (أذونات / تسجيل الدخول / تسجيل الدخول) مع معلومات المستخدم في JPA شخصية. برنامج Oracle Java EE Tutorial هو متفرق بعض الشيء على هذا (فقط Suvlets Servlets).

هذا هو بدون الاستفادة من إطار عمل آخر تماما، مثل أمن الربيع (ACEGI)، أو التماس، ولكن في محاولة للتمسك بالأمل مع نظام Java EE 6 الجديد (ملف تعريف الويب) إن أمكن.

هل كانت مفيدة؟

المحلول

بعد البحث في الويب ومحاولة العديد من الطرق المختلفة، إليك ما أقترحه مصادقة Java EE 6:

قم بإعداد عالم الأمان:

في حالتي، كان لدي المستخدمين في قاعدة البيانات. لذلك اتبعت هذا المنشور المدونات لإنشاء عالم JDBC يمكنه مصادقة المستخدمين بناء على اسم المستخدم وكلمات مرور MD5-MD5 في جدول قاعدة البيانات الخاصة بي:

http://blog.gamatam.com/2009/11/jdbc-realm-setup-with-glassfish-v3.html.

ملاحظة: إجراء محادثات حول مستخدم وجدول مجموعة في قاعدة البيانات. كان لدي فئة مستخدم مع سمة Enum Usertype تم تعيينها عبر التعليقات التوضيحية JAVAX.Perstence إلى قاعدة البيانات. قمت بتكوين المجال مع نفس الجدول للمستخدمين والمجموعات، باستخدام عمود Uperype كعمود المجموعة وعمل بشكل جيد.

استخدام مصادقة النموذج:

لا يزال يتبع Microsoft Blog Post، قم بتكوين Web.xml الخاص بك و Sun-Web.xml، ولكن بدلا من استخدام المصادقة الأساسية، استخدم النموذج (في الواقع، لا يهم أي واحد تستخدمه، ولكن انتهى بي الأمر باستخدام النموذج). استخدم HTML القياسي، وليس JSF.

ثم استخدم طرف بالدك أعلاه على كسول تهيئة معلومات المستخدم من قاعدة البيانات. اقترح القيام بذلك في الفاصوليا المدارة في الحصول على المدير من سياق الوجوه. استخدمت، بدلا من ذلك، فاصوليا للدورة الأمريكية لتخزين معلومات الجلسة لكل مستخدم، لذلك حقنت سياق الجلسة:

 @Resource
 private SessionContext sessionContext;

مع المدير، يمكنني التحقق من اسم المستخدم واستخدام مدير كيان EJB، احصل على معلومات المستخدم من قاعدة البيانات وتخزينها في بلدي SessionInformation EJB.

تسجيل خروج:

نظرت أيضا حول أفضل طريقة لتسجيل الخروج. أفضل ما وجدته هو استخدام Servlet:

 @WebServlet(name = "LogoutServlet", urlPatterns = {"/logout"})
 public class LogoutServlet extends HttpServlet {
  @Override
  protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
   HttpSession session = request.getSession(false);

   // Destroys the session for this user.
   if (session != null)
        session.invalidate();

   // Redirects back to the initial page.
   response.sendRedirect(request.getContextPath());
  }
 }

على الرغم من أن إجابتي متأخرا حقا بالنظر في تاريخ السؤال، آمل أن يساعد ذلك الأشخاص الآخرين الذين ينتهي بهم الأمر هنا من جوجل، تماما كما فعلت.

كياو،

Vítor Souza.

نصائح أخرى

أفترض أنك تريد المصادقة القائمة على النموذج استخدام واصفات النشر و j_security_check.

يمكنك أيضا القيام بذلك في JSF فقط باستخدام نفس أسماء الحقول غير المميزة j_username و j_password كما يتضح في البرنامج التعليمي.

على سبيل المثال

<form action="j_security_check" method="post">
    <h:outputLabel for="j_username" value="Username" />
    <h:inputText id="j_username" />
    <br />
    <h:outputLabel for="j_password" value="Password" />
    <h:inputSecret id="j_password" />
    <br />
    <h:commandButton value="Login" />
</form>

يمكنك أن تفعل التحميل كسول في User الحصول على التحقق مما إذا كان User يتم تسجيل الدخول بالفعل وإذا لم يكن كذلك، ثم تحقق مما إذا كان Principal موجود في الطلب وإذا كان الأمر كذلك، ثم احصل على User مرتبط ب j_username.

package com.stackoverflow.q2206911;

import java.io.IOException;
import java.security.Principal;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.context.FacesContext;

@ManagedBean
@SessionScoped
public class Auth {

    private User user; // The JPA entity.

    @EJB
    private UserService userService;

    public User getUser() {
        if (user == null) {
            Principal principal = FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
            if (principal != null) {
                user = userService.find(principal.getName()); // Find User by j_username.
            }
        }
        return user;
    }

}

ال User من الواضح أن إمكانية الوصول إليها في JSF EL #{auth.user}.

لتسجيل الخروج القيام HttpServletRequest#logout() (وحدد User إلى null!). يمكنك الحصول على مقبض HttpServletRequest في JSF بقلم ExternalContext#getRequest(). وبعد يمكنك أيضا إبطال الجلسة تماما.

public String logout() {
    FacesContext.getCurrentInstance().getExternalContext().invalidateSession();
    return "login?faces-redirect=true";
}

بالنسبة إلى بقايا (تحديد المستخدمين والأدوار والقيود في واصف النشر والجمهور)، ما عليك سوى اتباع البرنامج التعليمي Java EE 6 ووثائق Servletcontainer الطريقة المعتادة.


تحديث: يمكنك أيضا استخدام Servlet 3.0 الجديد HttpServletRequest#login() للقيام بتسجيل الدخول البرنامجي بدلا من استخدام j_security_check التي قد لا يمكن الوصول إليها من قبل المرسل في بعض Servletcontainers. في هذه الحالة، يمكنك استخدام نموذج JSF الكامل. username و password الخصائص و login الطريقة التي تبدو وكأنها هذه:

<h:form>
    <h:outputLabel for="username" value="Username" />
    <h:inputText id="username" value="#{auth.username}" required="true" />
    <h:message for="username" />
    <br />
    <h:outputLabel for="password" value="Password" />
    <h:inputSecret id="password" value="#{auth.password}" required="true" />
    <h:message for="password" />
    <br />
    <h:commandButton value="Login" action="#{auth.login}" />
    <h:messages globalOnly="true" />
</h:form>

وهذه الرأي الفاصوليا المدارة المذكورة والتي تتذكر أيضا الصفحة المطلوبة في البداية:

@ManagedBean
@ViewScoped
public class Auth {

    private String username;
    private String password;
    private String originalURL;

    @PostConstruct
    public void init() {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        originalURL = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_REQUEST_URI);

        if (originalURL == null) {
            originalURL = externalContext.getRequestContextPath() + "/home.xhtml";
        } else {
            String originalQuery = (String) externalContext.getRequestMap().get(RequestDispatcher.FORWARD_QUERY_STRING);

            if (originalQuery != null) {
                originalURL += "?" + originalQuery;
            }
        }
    }

    @EJB
    private UserService userService;

    public void login() throws IOException {
        FacesContext context = FacesContext.getCurrentInstance();
        ExternalContext externalContext = context.getExternalContext();
        HttpServletRequest request = (HttpServletRequest) externalContext.getRequest();

        try {
            request.login(username, password);
            User user = userService.find(username, password);
            externalContext.getSessionMap().put("user", user);
            externalContext.redirect(originalURL);
        } catch (ServletException e) {
            // Handle unknown username/password in request.login().
            context.addMessage(null, new FacesMessage("Unknown login"));
        }
    }

    public void logout() throws IOException {
        ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
        externalContext.invalidateSession();
        externalContext.redirect(externalContext.getRequestContextPath() + "/login.xhtml");
    }

    // Getters/setters for username and password.
}

بهذه الطريقة User يمكن الوصول إليها في JSF El by #{user}.

يجب ذكر أنه خيار ترك مشكلات المصادقة بالكامل على وحدة التحكم الأمامية، مثل خادم الويب Apache وتقييم httpservletrequest.getRemotuser () بدلا من ذلك، وهو تمثيل Java لمتغير بيئة Remote_user. هذا يسمح أيضا بتسجيل الدخول المتطور في التصميمات مثل مصادقة Shibboleth. يعد طلبات تصفية حاوية Servlet من خلال خادم ويب تصميم جيد لبيئات الإنتاج، وغالبا ما يتم استخدام mod_jk للقيام بذلك.

المشكلة httpservletrequest.login لا يضع حالة المصادقة في الجلسة تم إصلاحه في 3.0.1. تحديث Glassfish إلى أحدث إصدار وأنت انتهيت.

التحديث واضحة تماما:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top