سؤال

أنا أكتب تطبيق ويب Java الذي يحتاج إلى أداء تسجيل الدخول عبر Webservice. بالطبع، لا يمكن لأي من العوالم المقدمة مع خادم التطبيقات التي أستخدمها (Glassfish v2) القيام بالحيلة. لذلك اضطررت إلى كتابة بلدي. ومع ذلك، يبدو أن تنفيذ العالم الذي كتبته هو مرتبط تماما بالأزراء النباتية ولا يمكن استخدامه كما هو الحال في أي خوادم تطبيقات أخرى.

هل هناك أي طريقة قياسية أو مدعومة على نطاق واسع لتنفيذ عالم مخصص؟ هل هو بأي طريقة ممكنة لنشر هذا المجال من .war، أو هل تحتاج دائما إلى تحميلها من ClassPath الخاص بالخادم؟

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

المحلول

ملاحظة: الإجابة أدناه صالحة فقط ل Java EE 5. كما جددت انتباهي في أحد الإجابات الأخرى، فإن Java EE 6 يدعم ذلك. لذلك إذا كنت تستخدم Java EE 6، فلا تقرأ هذه الإجابة، ولكن قراءة الإجابة الأخرى ذات الصلة.

من البحوث الخاصة بي وإلى الإجابات على هذا السؤال هو الإجابة التي وجدتها هي ما يلي: على الرغم من أن JAAS هي واجهة قياسية، إلا أنه لا توجد طريقة موحدة لكتابة وتنشر ودمج LogyModule jaas realm + في خوادم التطبيق المختلفة.

يتطلب منك Glassfish V2 أن تقوم بتوسيع بعض الطبقات الداخلية الخاصة به التي تنفذ LoginModule أو عالم أنفسهم. ومع ذلك، لا يمكنك تخصيص عملية تسجيل الدخول بأكملها نظرا لأن العديد من طرق واجهة LoginModule يتم وضع علامة نهائية في Superclass في Glassfish. يجب وضع فئات LogyModule المخصصة ودروس العالم في كصفها ClassPath (وليس التطبيق)، ويجب أن يتم تسجيل المجال يدويا (بدون نشر من .WAR ممكن).

يبدو أن الوضع أفضل قليلا بالنسبة ل Tomcat، والذي سيتيح لك رمز عالمك الخاص وتسجيل الدخول بالكامل، ثم قم بتكوينها في خادم التطبيق باستخدام JaasRealm الخاص به (والذي سيوفه العمل الفعلي إلى تطبيقات عملك و LOGNModule) وبعد ومع ذلك، حتى Tomcat لا يسمح بنشر عالمك المخصص من .war.

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

للرجوع اليها، ولأنه سئل في التعليقات على سؤالي، هنا هو الرمز الذي كتبته ل Glassfishv2.

بادئ ذي بدء، وهنا تنفيذ عالم:

public class WebserviceRealm extends AppservRealm {

private static final Logger log = Logger.getLogger(WebserviceRealm.class.getName());

private String jaasCtxName;
private String hostName;
private int port;
private String uri;

@Override
protected void init(Properties props) throws BadRealmException, NoSuchRealmException {
    _logger.info("My Webservice Realm : init()");

    // read the configuration properties from the user-supplied properties,
    // use reasonable default values if not present
    this.jaasCtxName = props.getProperty("jaas-context", "myWebserviceRealm");
    this.hostName = props.getProperty("hostName", "localhost");
    this.uri = props.getProperty("uri", "/myws/EPS");

    this.port = 8181;
    String configPort = props.getProperty("port");
    if(configPort != null){
        try{
            this.port = Integer.parseInt(configPort);
        }catch(NumberFormatException nfe){
            log.warning("Illegal port number: " + configPort + ", using default port (8181) instead");
        }
    }
}

@Override
public String getJAASContext() {
    return jaasCtxName;
}

public Enumeration getGroupNames(String string) throws InvalidOperationException, NoSuchUserException {
    List groupNames = new LinkedList();
    return (Enumeration) groupNames;
}

public String getAuthType() {
    return "My Webservice Realm";
}

public String getHostName() {
    return hostName;
}

public int getPort() {
    return port;
}

public String getUri() {
    return uri;
}
}

ثم تنفيذ تسجيل الدخول:

public class WebserviceLoginModule extends AppservPasswordLoginModule {

// all variables starting with _ are supplied by the superclass, and must be filled
// in appropriately

@Override
protected void authenticateUser() throws LoginException {
    if (_username == null || _password == null) {
        throw new LoginException("username and password cannot be null");
    }

    String[] groups = this.getWebserviceClient().login(_username, _password);

    // must be called as last operation of the login method
    this.commitUserAuthentication(groups);
}

@Override
public boolean commit() throws LoginException {
    if (!_succeeded) {
        return false;
    }

    // fetch some more information through the webservice...

    return super.commit();
}

private WebserviceClient getWebserviceClient(){
    return theWebserviceClient;
}
}

أخيرا، في المجال يجب ربط ل LOGNModule. تتم أضف الأسطر التالية في نهاية هذا الملف:

myWebserviceRealm { // use whatever String is returned from you realm's getJAASContext() method
    my.auth.login.WebserviceLoginModule required;
};

هذا هو ما حصلت على الأشياء التي تعمل من أجلي على glashfish. مرة أخرى، هذا الحل غير محمول عبر خوادم التطبيق، ولكن بقدر ما أستطيع أن أقول، لا يوجد حل محمول موجود.

نصائح أخرى

هل هناك أي طريقة قياسية أو مدعومة على نطاق واسع لتنفيذ عالم مخصص؟ هل هو بأي طريقة ممكنة لنشر هذا المجال من .war، أو هل تحتاج دائما إلى تحميلها من ClassPath الخاص بالخادم؟

هناك طريقة قياسية قياسية لتطبيق عالم مخصص، أو بأكثر واقعية وحدة مصادقة مخصصة. هذا يمكن القيام به عبر Jaspic / Jaspi / JSR 196 SPI / API. وبعد Jaspic هو جزء قياسي من أي تطبيق Java EE 6 الكامل، ولكن لسوء الحظ، ليس جزءا من ملف تعريف Java EE 6.

ومع ذلك، على الرغم من أن Jaspic يجري جزءا من Java EE 6، فإنه لا يدعمه البائعون بشكل صحيح. يبدو أن Glassfish و WeBlogic لديها تطبيقات جيدة جدا، و JBOSS AS و GERONIMO أكثر إشكالية بعض الشيء. وقد ذكر مهندس الرصاص من JBoss على هذا الموضوع (أنيل سالداانا) حتى أنه يرفض تنشيط Jaspic افتراضيا في الوقت الحالي. عدد قليل من الأخطاء الأكثر حدة في JBOSS AS 7.1 ثابت مؤخرا, ولكن نظرا لعدم وجود إطلاقات علنية من JBoss 7.1.X المجدولة بعد الآن و JBOSS AS 7.2 لا يزال هناك بعض الوقت فهذا يعني حتى الآن على الأقل على JBOSS JASPISH مزعجة.

قضية أخرى مؤسفة هي أن وحدة المصادقة الفعلية قد تكون موحدة، ولكن لا توجد طريقة إعلانية (قراءة ملف XML) لتكوينه موحد.

هل هو بأي طريقة ممكنة لنشر هذا المجال من .war، أو هل تحتاج دائما إلى تحميلها من ClassPath الخاص بالخادم؟

مع Jaspic، يمكن بالفعل تحميل وحدة المصادقة ("المجال") بالفعل من .war. أنا لست متأكدا 100٪ عما إذا كان مضمونا من قبل المواصفات، ولكن من الخوادم الأربعة التي اختبرتها (سمكة زجاجية، Weblogic، Geronimo و JBOSS AS)، فكلوا أيدوا ذلك. لدى Geronimo لسوء الحظ نوع من حالة السباق في تسجيله البرنامجي، لذلك تحتاج إلى حل كبير من خلال القيام بنشر ساخن مرتين، ولكن في النهاية إذا قمت بتحميل الوحدة النمطية من .war.

اعتبارا من الآليات الملكية، على الأقل JBOSS كما دعمت دائما تحميل الوحدة النمطية (مثل فئة فرعية من Org.jboss.security.auth.sec.bi.abstractserverloginmodule) من .war أو.

أنا كتب آخر بلوق حول هذا الموضوع مؤخرا لديه المزيد من التفاصيل.

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

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

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

إذا كنت ترغب في جعل هذا أكثر قابلية للاستخدام، فأنا أقترح وضع الجزء الأكبر من التنفيذ في برنامج تشغيل مخصص تم تطويره مقابل واجهة Javaee (S) القياسية ثم وجود طبقة تنمذ رقيقة خاصة بالمندوبين في التنفيذ المعياري المحتمل وبعد

الدفع صالة الشمس حول هذا الموضوع.

لم أفعل ذلك في الواقع هذا بنفسي، لكنني واثق من ذلك، كما يمنحك كل خيار لتسجيل العوالم الجديدة (مجالات الأمان) على ذلك.

ربما لن تكون محمولة بنسبة 100٪، ولكل منها قد تحتاج إلى جهاز XML مختلفا XML، ولكن بشكل أساسي، لا يوجد سبب للرمز ليكون مختلفا.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top