Quantcast
Channel: Blog – Stormpath User Identity API
Viewing all articles
Browse latest Browse all 278

User Authentication in Java 8

$
0
0

Java 8 added many new features that both modernize and simplify the language. Today, I’ll walk you through how some of these new features impact authentication, authorization, and user management. We’ll explore a few of the most important new features, including: Lambdas, method references, and Streams. But first, some background on Stormpath and the code that backs this post which can be found here.

Stormpath: Never Built Auth Again

The Stormpath Spring Boot WebMVC Integration adds default views to your app for common authentication and authorization workflows. This includes registration, login, and forgot password, among others. You get all of this for your application with no additional programming on your part.

Getting setup with Stormpath is super easy and it’s totally free to start. Follow the QuickStart here to create a Stormpath account.

Even easier: click the friendly Heroku Deploy button below to deploy the example app to your Heroku account including the provisioning of a Stormpath Account!

Deploy

All that’s required to add the Stormpath integration to your Spring Boot WebMVC project is a single dependency:


    com.stormpath.spring
    stormpath-thymeleaf-spring-boot-starter
    ${stormpath.version}

Boom! Instant authentication!

Lambdas: Reduce Boilerplate and Add Functional Programming

The Stormpath Spring Boot integration includes as a feature the ability to have registration and login pre and post handlers. This is handy for triggering secondary functionality, like logging events or sending messages when someone registers or logs in.

Prior to Java 8, you’d set this up with an anonymous instantiation of the WebHandler interface. It looks like this:

@Bean
public WebHandler registerPreHandler() {
    return new WebHandler() {
        @Override
        public boolean handle(HttpServletRequest req, HttpServletResponse res, Account account) {
            log.info("----> PreRegisterHandler");
            return true;
        }
    };
}

Here’s the lambda version of the same thing:

@Bean
public WebHandler registerPreHandler() {
    return (HttpServletRequest request, HttpServletResponse response, Account account) -> {
        log.info("----> PreRegisterHandler");
        return true;
    };
}

Aside from reducing the code by four lines, it demonstrates how lambdas reduce boilerplate code and implement functional interfaces. A functional interface has a specific definition: an interface that contains a single abstract method declaration.

In the above example, Java is able to infer the correct type to create based on the return type of registerPreHandler, which is WebHandler. This can be further simplified by removing the parameter types as Java can infer that as well. For single-line implementations, the code can be even further reduced:

@Bean
public WebHandler loginPostHandler() {
    return (request, response, account) -> account != null;
}

Method References: Small and Readable

When using the Stormpath Java SDK, you are often working with a collection of some sort, say Accounts, for instance. The interface for a collection of Accounts is AccountList. We often get the question, why not just have: List<Account>? The reason is that we support auto-paging and an AccountList has its own href as it extends the Resource interface as well. Auto-paging is a built in capability whereby the implementation will fetch the next page of data without you having to manage that manually.

The bottom line is that you’ll often want to transform your results into a form that is easily serializable and can be converted automatically by Spring Boot into a json response.

The first thing we want to do is to take our results and load them (or a portion of them) into a list. In the old days of Java 7, we would do something like this:

List accountList = new ArrayList<>();
AccountList accounts = application.getAccounts(Accounts.criteria().limitTo(LIMIT));
for (Account account : accouns) {
    accountList.add(account);
}

In Java 8, we can write a much more terse version of the same thing. Each of the following accomplishes the same thing:

// making use of lambdas
accounts.forEach((Account a) -> {
    accountList.add(a);
});

// since it’s one line, we don’t need the braces and Java can infer the type
accounts.forEach(a -> accountList.add(a));

// method reference for the win
accounts.forEach(accountList::add);

When both the parameter type in the iterator and the parameter being passed into a method can be inferred, you can use a method reference in the form of <variable>::<method>.

It’s still very clear what is going on reading the code, but it is significantly more terse.

You can use both method references and constructor references in Java 8. For more on this, look here.

Streams: Fun with Collections

For the sake of this example, here’s the setup: We want to get back a list of Accounts, limited to a result size of 50. We only want to include accounts where the email address does not end in stormpath.com AND, we only want to return certain fields of each Account in a JSON response.

Here’s the old-school approach:

public List accounts() {
    List accountDetails = new ArrayList<>();
    AccountList accounts = application.getAccounts(Accounts.criteria().limitTo(LIMIT));

    for (Account a : accounts) {
        if (!a.getEmail().contains("@stormpath.com")) {
            accountDetails.add(new AccountDetails(
                a.getGivenName(), a.getSurname(), a.getFullName(), a.getEmail(), a.getUsername()
            ));
        }
    }

    return accountDetails;
}

Here’s the approach with lambdas and streams:

public List accountsLambda() {
    AccountList accounts = application.getAccounts(Accounts.criteria().limitTo(LIMIT));

    List accountList = new ArrayList<>();
    accounts.forEach(accountList::add);
    
    return accountList.parallelStream()
        .filter(a -> !a.getEmail().contains("@stormpath.com"))
        .map(a -> new AccountDetails(
            a.getGivenName(), a.getSurname(), a.getFullName(), a.getEmail(), a.getUsername()
        ))
        .collect(Collectors.toList());
}

Both versions return the exact same results. The second example represents a much more functional approach. Additionally, it has some efficiencies that can make the response time faster, especially for large result sets. We’ll look at that in a moment, but first, a disclaimer:

Line 5 is necessary as the AccountList interface does not yet support the new streams interface. It is therefore necessary in this example to first convert our AccountList into a List<Account>. In upcoming releases of the Stormpath Java SDK, we will integrate the new Java 8 interfaces into our collection classes.

On line 7, we take our List object and get a parallelStream from it. This is a powerful new feature of Java 8 that takes advantage of multi-core processors without you having to do any specialized programming. That is, without any changes to your code, the more cores the machine the example is running on, the faster it will run.

On line 8, we use the filter method to exclude those Accounts where the email ends with stormpath.com. The filter method returns back the stream, allowing us to chain methods together.

Lines 9 – 11 use the map method to easily transform the Account object into an AccountDetails object, which is easily converted to JSON by Spring Boot. The map method also returns a stream, so we can continue chaining. However, the stream is returns is of type AccountDetails now: Stream<AccountDetails>.

Finally, line 12 collects what’s coming from the stream into a list of type AccountDetails, which is what we return from the method.

The filter and map methods are referred to as “intermediate stream operations”, while the collect method is referred to as a “terminal stream operation”.

Which Java is Right for You?

With the 1.0 release of the Java SDK, Stormpath officially ended support for Java 6. We’ve seen continuous growth for Java 8 adoption over the last year and it is now in the majority in terms of Java version in use with Stormpath. That said, many of our customers are still on Java 7. Oracle officially ended updates for Java 7 in April, 2015 and Java 9 will be released in 2017.

So, what does all that mean? While the older Java 7 language constructs will continue to work, the Java 8 functional interfaces for Lambdas and Streams are the way to go to get the most out of your multi-core production environment.

Learn More

Interested in learning more about user authentication in Java or Spring Boot? We have some great resources for you to check out!

  • Web App Tutorial – Spring Boot + Stormpath
  • Token Auth for Spring Boot + Stormpath
  • SSO with Spring Boot + Stormpath
  • The post User Authentication in Java 8 appeared first on Stormpath User Identity API.


    Viewing all articles
    Browse latest Browse all 278

    Trending Articles