Java >> Java tutorial >  >> Tag >> HTTP

Wicket HTTPS-vejledning, del tre:Oprettelse af en sikker formularindsendelse fra en ikke-sikker side

Den tredje del af min Wicket HTTPS-tutorial beskriver, hvordan du kan indsende en formular ved at bruge HTTPS-protokol, når formularen føjes til en ikke-sikker side (serveret over HTTP).

Dette er et noget almindeligt tilfælde i webapplikationer, selvom det overtræder det grundlæggende princip for HTTPS-protokollen (tillid).

Derfor følte jeg mig forpligtet til at give en løsning på det.

Du bør ikke bruge denne tilgang i din Wicket-applikation . Hvis du overvejer at bruge denne tilgang i din ansøgning, skal du læse et blogindlæg med titlen:Din loginformular sender til HTTPS, men du blæste den, da du indlæste den over HTTP.

Påkrævede trin

Vores mål kan nås ved at følge disse trin:

  1. Aktivering og konfiguration af HTTPS-understøttelse af Apache Wicket
  2. Oprettelse af loginformularen, som sender sig selv til en sikker url
  3. Tilføjelse af den oprettede loginformular til en ikke-sikker side
  4. Oprettelse af en sikker side, som behandler oplysningerne i loginformularen

Hvis du ikke er bekendt med HTTPS-understøttelsen af ​​Apache Wicket, bør du læse første og anden del af min Wicket HTTPS-tutorial, fordi jeg vil springe de begreber over, som er introduceret i mine tidligere blogindlæg.

Oprettelse af loginformularen

Oprettelse af loginformular er opdelt i to mindre faser:

  • Oprettelse af en url-generator, som genererer login-url'en
  • Oprettelse af selve loginformularen

Jeg vil herefter beskrive disse faser.

Først oprettede jeg en url-generator, som er i stand til at generere den absolutte login-url. Implementeringen af ​​url-generatoren er følgende:

public class UrlGenerator {
    private static final char CONTEXT_PATH_SEPARATOR = '/';

    public static String generateAbsoluteLoginUrl(String protocol, Integer port, HttpServletRequest request) {
        StringBuilder urlBuilder = new StringBuilder();

        urlBuilder.append(protocol);
        urlBuilder.append("://");
        urlBuilder.append(request.getServerName());
        if (port != null) {
            urlBuilder.append(":");
            urlBuilder.append(port);
        }

        String contextPath = request.getContextPath();

        if (contextPath != null) {
            urlBuilder.append(contextPath);
            if (!contextPath.isEmpty() && contextPath.charAt(contextPath.length()-1) != CONTEXT_PATH_SEPARATOR) {
                urlBuilder.append(CONTEXT_PATH_SEPARATOR);
            }
        }

        urlBuilder.append(WicketApplication.LOGIN_HANDLER_PATH);

        return urlBuilder.toString();
    }
}

For det andet oprettede jeg en login-formular, som opretter en absolut handlings-url. Handlings-url-adressen for en formular kan manipuleres ved at overskrive onComponentTag() metode. Implementeringen af ​​denne metode bør oprette den absolutte handlings-url og erstatte den relative handlings-url med den. Min implementering bruger UrlGenerator klasse for at oprette den sikre login-url. Kildekoden til loginformularen er angivet i følgende:

public class LoginForm extends StatelessForm<LoginDTO> {

    private static final String TAG_ATTRIBUTE_ACTION_NAME = "action";
    private static final String PROTOCOL_HTTPS_PREFIX = "https";

    private static final String WICKET_ID_FEEDBACK = "feedback";
    private static final String WICKET_ID_USERNAME = "username";
    private static final String WICKET_ID_PASSWORD = "password";

    public LoginForm(String id) {
        super(id, new CompoundPropertyModel(new LoginDTO()));
        init();
    }

    public LoginForm(String id, IModel iModel) {
        super(id, iModel);
        init();
    }

    private void init() {
        add(new FeedbackPanel(WICKET_ID_FEEDBACK));
        add(new TextField(WICKET_ID_USERNAME)
                .setRequired(true)
        );
        add(new PasswordTextField(WICKET_ID_PASSWORD)
                .setRequired(true)
        );
    }

    @Override
    protected void onComponentTag(ComponentTag tag) {
        super.onComponentTag(tag);

        HttpServletRequest request = this.getWebRequest().getHttpServletRequest();

        //Create an absolute url, which points to a page used to process login information
        String securedAbsoluteActionUrl = UrlGenerator.generateSecureLoginUrl(PROTOCOL_HTTPS_PREFIX, WicketApplication.HTTPS_PORT, request);

        tag.put(TAG_ATTRIBUTE_ACTION_NAME, securedAbsoluteActionUrl);
    }
}

Tilføjelse af loginformularen til en ikke-sikker side

Det næste trin er at tilføje login-formularen til en ikke-sikker side. Kildekoden til login-siden er angivet i følgende:

public class LoginPage extends WebPage {
    private static final String WICKET_ID_HOMEPAGE_LINK = "homepageLink";
    private static final String WICKET_ID_LOGINFORM = "loginForm";

    public LoginPage(PageParameters parameters) {
        super(parameters);
        init();
    }

    protected void init() {
        add(new BookmarkablePageLink(WICKET_ID_HOMEPAGE_LINK, HomePage.class));
        add(new LoginForm(WICKET_ID_LOGINFORM));
    }
}

Oprettelse af en sikker side til behandling af loginoplysningerne

Det sidste trin er at oprette en sikker side, som behandler de givne loginoplysninger. Denne side implementerer følgende funktioner:

  • Formularvalidering . Da oprettelsen af ​​en absolut login-url ser ud til at omgå den indbyggede formularvalideringsunderstøttelse af Apache Wicket, bør siden bekræfte, at både brugernavn og adgangskode er indtastet.
  • Login . Loginbehandlersiden skal bekræfte, at brugernavnet og adgangskoden, som brugeren har indtastet, er gyldige.
  • Flowkontrol . Hvis login er gyldigt, omdirigeres brugeren til applikationens hjemmeside. Ellers bliver brugeren omdirigeret tilbage til login-siden.

Kildekoden til login-behandlersiden er angivet i følgende:

@RequireHttps
public class LoginHandlerPage extends WebPage {

    private final String MESSAGE_KEY_LOGIN_FAILED = "error.login.failed";
    private final String MESSAGE_KEY_PASSWORD_EMPTY = "loginForm.password.Required";
    private final String MESSAGE_KEY_USERNAME_EMPTY = "loginForm.username.Required";

    private final String PARAM_USERNAME = "username";
    private final String PARAM_PASSWORD = "password";

    private final String USERNAME = "foo";
    private final String PASSWORD = "bar";

    public LoginHandlerPage(final PageParameters parameters) {
        String username = parameters.getString(PARAM_USERNAME);
        String password = parameters.getString(PARAM_PASSWORD);

        boolean requiredInformationEntered = isRequiredInformationEntered(username, password);

        if (requiredInformationEntered) {
            if (isLoginValid(username, password)) {
                storeUserInfoToSession(username);
                redirectToTargetPage(HomePage.class);
            }
            else {
                //Sets a feedback message to session. This is necessary,
                //because the feedback message must exists across requests.
                getSession().error(getString(MESSAGE_KEY_LOGIN_FAILED));
                redirectToTargetPage(LoginPage.class);
            }
        }
        else {
            redirectToTargetPage(LoginPage.class);
        }
    }

    /**
     * Wicket built-in validation is not done (I guess the reason is the generation
     * of absolute url, which bypasses some of Wicket Form functions). This method
     * validates that the username and password are entered.
     * @param username
     * @param password
     * @return  true if both username and password are entered and false otherwise.
     */
    private boolean isRequiredInformationEntered(String username, String password) {
        boolean isValidLogin = true;

        if (username.isEmpty()) {
            getSession().error(getString(MESSAGE_KEY_USERNAME_EMPTY));
            isValidLogin = false;
        }

        if (password.isEmpty()) {
            getSession().error(getString(MESSAGE_KEY_PASSWORD_EMPTY));
            isValidLogin = false;
        }

        return isValidLogin;
    }

    private void storeUserInfoToSession(String username) {
        WicketHttpsSession session = WicketHttpsSession.get();
        //Invalidates the current session and creates a new secure session.
        //The created secure session cannot be accessed when using http
        //protocol. This option should be used when only https protocol is
        //used after the user has logged in.
        //session.replaceSession();
        session.setAuthenticatedUsername(username);
    }

    private boolean isLoginValid(String username, String password) {
        if (username.equals(USERNAME) && password.equals(PASSWORD)) {
            return true;
        }
        return false;
    }

    private void redirectToTargetPage(Class pageClass) {
        setResponsePage(pageClass);
    }
}

Afsluttende ord

Jeg har nu beskrevet, hvordan du kan oprette en sikker formularindsendelse fra en side, som serveres over HTTP-protokol. Du kan også downloade et eksempel på et Maven-projekt, som er testet med Apache Wicket 1.4.15. Den indeholder den komplette kildekode til et simpelt eksempelprogram, og forhåbentlig vil det hjælpe dig til at få en bedre forståelse af begreberne, som er beskrevet i dette blogindlæg.

OPDATERING :Du bør også tjekke blogindlægget skrevet af George Armhold:Wicket:indsende en formular over SSL fra en usikret side. Hans løsning på dette problem er en smule renere end min.


Java tag