J_security_check का उपयोग करके जावा EE / JSF में उपयोगकर्ता प्रमाणीकरण करना


156

मैं सोच रहा हूं कि जेएसएफ 2.0 (और यदि कोई भी घटक मौजूद है) का उपयोग करने वाले वेब एप्लिकेशन के लिए उपयोगकर्ता प्रमाणीकरण के बारे में वर्तमान दृष्टिकोण क्या है और जावा ईई 6 कोर तंत्र (लॉगिन / जांच की अनुमति / लॉगआउट) उपयोगकर्ता जानकारी के साथ जेपीए में रखते हैं इकाई। ओरेकल जावा ईई ट्यूटोरियल इस पर थोड़ा विरल है (केवल हैंडल को संभालता है)।

यह स्प्रिंग-सिक्योरिटी (एसेगी), या सीम की तरह एक पूरे अन्य ढांचे का उपयोग किए बिना है , लेकिन यदि संभव हो तो नए जावा ईई 6 प्लेटफॉर्म (वेब ​​प्रोफाइल) के साथ उम्मीद करने की कोशिश कर रहा है।

जवाबों:


85

वेब पर खोज करने और कई अलग-अलग तरीकों की कोशिश करने के बाद, यहाँ मैं जावा ईई 6 प्रमाणीकरण के लिए क्या सुझाव दूंगा:

सुरक्षा क्षेत्र सेट अप करें:

मेरे मामले में, मेरे पास डेटाबेस में उपयोगकर्ता थे। इसलिए मैंने एक JDBC क्षेत्र बनाने के लिए इस ब्लॉग पोस्ट का अनुसरण किया, जो मेरे डेटाबेस तालिका में उपयोगकर्ता नाम और MD5- हैशेड पासवर्ड के आधार पर उपयोगकर्ताओं को प्रमाणित कर सकता है:

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

नोट: पोस्ट डेटाबेस में एक उपयोगकर्ता और एक समूह तालिका के बारे में बात करता है। मैं एक उपयोगकर्ता वर्ग के साथ एक उपयोगकर्ता वर्ग enum विशेषता javax.persistence एनोटेशन डेटाबेस के माध्यम से मैप किया गया था। मैंने उपयोगकर्ताओं और समूहों के लिए एक ही तालिका के साथ दायरे को कॉन्फ़िगर किया, उपयोगकर्ता कॉलम कॉलम समूह के रूप में उपयोग किया और यह ठीक काम किया।

फॉर्म प्रमाणीकरण का उपयोग करें:

अभी भी उपरोक्त ब्लॉग पोस्ट के बाद, अपने web.xml और sun-web.xml को कॉन्फ़िगर करें, लेकिन BASIC प्रमाणीकरण का उपयोग करने के बजाय, FORM का उपयोग करें (वास्तव में, इससे कोई फर्क नहीं पड़ता कि आप किसका उपयोग करते हैं, लेकिन मैंने FORM का उपयोग करके समाप्त कर दिया है)। जेएसएफ नहीं, मानक HTML का उपयोग करें।

फिर डेटाबेस से उपयोगकर्ता की जानकारी को आलसी करते हुए ऊपर BalusC के टिप का उपयोग करें। उन्होंने चेहरे के संदर्भ से प्रिंसिपल प्राप्त करने में एक प्रबंधित बीन में ऐसा करने का सुझाव दिया। इसके बजाय, मैंने प्रत्येक उपयोगकर्ता के लिए सत्र जानकारी संग्रहीत करने के लिए एक स्टेटफुल सत्र बीन का उपयोग किया, इसलिए मैंने सत्र संदर्भ को इंजेक्ट किया:

 @Resource
 private SessionContext sessionContext;

प्रिंसिपल के साथ, मैं उपयोगकर्ता नाम की जांच कर सकता हूं और, ईजेबी इकाई प्रबंधक का उपयोग करके, डेटाबेस से उपयोगकर्ता जानकारी प्राप्त कर सकता हूं और मेरे SessionInformationईजेबी में स्टोर कर सकता हूं ।

लॉग आउट:

मैंने लॉगआउट करने के सर्वोत्तम तरीके के लिए भी चारों ओर देखा। सबसे अच्छा जो मैंने पाया है वह एक सर्वलेट का उपयोग कर रहा है:

 @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());
  }
 }

यद्यपि मेरा उत्तर प्रश्न की तारीख को देखते हुए वास्तव में देर हो चुकी है, मुझे आशा है कि यह अन्य लोगों की मदद करता है जो Google से समाप्त होते हैं, जैसे मैंने किया था।

Ciao,

विटोर सूजा


15
सलाह का एक छोटा शब्द: आप request.getSession (झूठा) का उपयोग कर रहे हैं और उस पर अमान्य () कॉल कर रहे हैं। यदि कोई सत्र नहीं है, तो request.getSession (झूठा) शून्य हो सकता है। बेहतर जाँच करें कि क्या यह पहले शून्य है?)
अर्जन टिज़म्स

@Vitor: हाय। क्या आप के बारे में कुछ कहना पसंद करते हैं जब यह कंटेनर आधारित सुरक्षा से shiro या अन्य जैसे विकल्पों के लिए अच्छा है? : यहाँ और अधिक ध्यान केंद्रित सवाल देखें stackoverflow.com/questions/7782720/...
रजत गुप्ता

ऐसा लगता है कि ग्लासफिश JDBC दायरे, नमकीन पासवर्ड हैश का भंडारण करने का समर्थन नहीं करता है। क्या उस मामले में इसका उपयोग करना वास्तव में सबसे अच्छा अभ्यास है?
Lii

क्षमा करें, आपकी सहायता नहीं कर सकता। मैं ग्लासफिश विशेषज्ञ नहीं हूं। हो सकता है कि उस प्रश्न को एक नए सूत्र में पूछें कि लोग क्या कहते हैं?
वीटोर ई। सिल्वा सूज़ा

1
Lii, आप ग्लासफिश कंटेनर का उपयोग करके नमकीन के साथ काम कर सकते हैं। किसी भी हैश का उपयोग न करने के लिए अपने हील को कॉन्फ़िगर करें। यह आपके द्वारा पासवर्ड के लिए डाले गए सादे मूल्य की तुलना करेगा HttpServletResponse#login(user, password), इस तरह आप बस उपयोगकर्ता के नमक, पुनरावृत्तियों से प्राप्त कर सकते हैं और जो भी आप नमकीन के लिए उपयोग करते हैं, उस उपयोगकर्ता ने उस नमक का उपयोग करके दर्ज किया है और फिर कंटेनर को प्रमाणित करने के लिए कहेंगे HttpServletResponse#login(user, password)
एमपोर्टेला

152

मुझे लगता है कि आप तैनाती के विवरणों का उपयोग करके प्रपत्र आधारित प्रमाणीकरण चाहते हैं और ।j_security_check

जेएसएफ में आप केवल उसी पूर्वनिर्धारित क्षेत्र के नाम का उपयोग करके भी कर सकते हैं 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 ईएल में पहुँचा जा सकता है #{auth.user}

लॉगआउट करने के लिए एक HttpServletRequest#logout()(और Userनल करने के लिए सेट !)। आप HttpServletRequestJSF में से एक हैंडल प्राप्त कर सकते हैं ExternalContext#getRequest()। आप सत्र को पूरी तरह से अमान्य भी कर सकते हैं।

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

अवशेष (उपयोगकर्ताओं, भूमिकाओं और परिनियोजन वर्णनकर्ता और दायरे में परिभाषित करने के लिए) के लिए, बस जावा ईई 6 ट्यूटोरियल और सर्वलेट प्रलेखन का सामान्य तरीके से पालन करें।


अद्यतन : आप नए सर्वलेट 3.0 HttpServletRequest#login()का उपयोग करने के बजाय एक प्रोग्रामेटिक लॉगिन करने के लिए भी कर j_security_checkसकते हैं, जो कुछ सर्वलेटकनेक्टर्स में डिस्पैचर द्वारा प्रति-से-पहुंच योग्य नहीं हो सकता है। इस मामले में आप एक fullworthy 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.
}

इस तरह से UserJSF EL में पहुँचा जा सकता है #{user}


1
मैंने एक डिस्क्लेमर को शामिल करने के लिए प्रश्न को अपडेट किया जो j_security_checkसभी सर्वलेटकंटेनर पर काम नहीं कर सकता है।
BalusC

1
वेब अनुप्रयोगों के साथ प्रोग्राम सुरक्षा का उपयोग करने पर जावा ट्यूटोरियल से लिंक: java.sun.com/javaee/6/docs/tutorial/doc/gjiie.html (सर्वलेट का उपयोग करके): एक सर्वलेट क्लास पर आप इसका उपयोग कर सकते हैं: @WebServlet(name="testServlet", urlPatterns={"/ testServlet "}) @ServletSecurity(@HttpConstraint(rolesAllowed = {"testUser", "admin”})) और प्रति विधि पर स्तर: @ServletSecurity(httpMethodConstraints={ @HttpMethodConstraint("GET"), @HttpMethodConstraint(value="POST", rolesAllowed={"testUser"})})
ngeek

3
और आपकी बात ..? क्या यह JSF में लागू है? खैर, JSF में केवल एक सर्वलेट है, FacesServletऔर आप इसे संशोधित नहीं कर सकते (और नहीं करना चाहते)।
15

1
@BalusC - जब आप ऊपर कहते हैं कि आप j_security_check या प्रोग्रामेटिक लॉगिन का उपयोग करने का सबसे अच्छा तरीका है?
सिमगिनेर

3
@simgineer: अनुरोधित URL नाम के साथ अनुरोधित विशेषता के रूप में उपलब्ध है RequestDispatcher.FORWARD_REQUEST_URI। अनुरोध विशेषताएँ JSF द्वारा उपलब्ध हैं ExternalContext#getRequestMap()
बालुसक

7

यह उल्लेख किया जाना चाहिए कि यह सामने नियंत्रक के लिए प्रमाणीकरण मुद्दों को पूरी तरह से छोड़ने का एक विकल्प है, उदाहरण के लिए एक अपाचे वेबसर्वर और इसके बजाय HttpServletRequest.getRemoteUser () का मूल्यांकन करें, जो REMOTE_USER पर्यावरण चर के लिए जावा प्रतिनिधित्व है। यह शिबोलेथ प्रमाणीकरण जैसे डिजाइनों में परिष्कृत लॉग की अनुमति देता है। वेब सर्वर के माध्यम से एक सर्वलेट कंटेनर के लिए फ़िल्टरिंग अनुरोध उत्पादन वातावरण के लिए एक अच्छा डिज़ाइन है, अक्सर ऐसा करने के लिए mod_jk का उपयोग किया जाता है।


4

HttpServletRequest.login समस्या सत्र में प्रमाणीकरण स्थिति को सेट नहीं करता है 3.0.1 में तय किया गया है। ग्लासफ़िश को नवीनतम संस्करण में अपडेट करें और आपका काम हो गया।

अपडेट करना काफी सरल है:

glassfishv3/bin/pkg set-authority -P dev.glassfish.org
glassfishv3/bin/pkg image-update

4
लिंक टूट गया है। आप किस मुद्दे का जिक्र कर रहे थे?
२०
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.