Leverage Spring Security to Handle Mobile Access to Your Grails App
Now that I have an AWESOME little mobile version of my grails appliction, why do I put myself through the pain of logging in through the standard login page? It gets to be a lot of pinch-zooming and thumb dragging (2x’s if I accidently mis-type your credentials with my fat fingers).
What I was looking to implement, was when a mobile browser came to my site (unauthorized), I wanted to show them a mobile login screen. Upon successful login, take them to a mobile landing page. From there, I will have links to the rest of the mobile site, as well as some links to the ‘standard’ view of the app as well.
I could have redesigned my login screen to apply different styles depending on media, but I’m not a great designer / styler. And then I’m left with writing my own mobile redirect type logic on my ‘standard’ landing page action. Plus trying to make sure that they always went to the mobile landing page upon successful login would be a pain here.
I could also just create a different mobile login screen. Determine what type of device the user was using on the server-side, and just change out the view that I wanted to render for login as well as after a successful login. All requests after the login would remain un-affected. The user could decide which side of the site they wanted to view. This one is looking promising!
Switch the View
When researching this last option, I found the spring-mobile plugin (not fully mature as of yet, but offered the feature I needed). It adds a dynamic method ‘withMobileDevice’ to all your Controller classes. I installed the plugin and changed my login rendering action. It worked! If I pulled up the app on my mobile device, I was directed to my mobile login screen. All were happy, the day was good!
I still, however, was not always being directed to the mobile version of my application at all times. If a mobile user pulled up my app with ‘myapp.com/nothelandingpage’, they were still taken to the standard ‘notthelandingpage’. This wasn’t horrible, but I wasn’t sure how to funnel them back into the mobile portion.
I WANTED a mobile user to be able to access the standard version of the site (since not all content would be translated to the mobile version), but figured that if the user came to my site with a mobile device, I should assume they want the mobile version.
Redirect a Mobile Login
I started looking into the spring-security-core plugin code. I remembered the defaultTargetUrl option that you can setup / override. What I wanted was something that worked similar.
I could override a step in the Spring Security filter chain process, similar to what we often do for the UserDetails piece, but the problem was which step. After a bit of work with Google, I found this site. His approach was almost dead on to what I wanted to do with handling the landing page problem. Instead of changing the target by roles, I was going to do it by device.
To determine the device, I peeked in the SpringMobileGrailsPlugin.groovy file and saw how they implemented ‘withMobileDevice()’. They were using a DeviceResolver bean to grab the info. It was already wired up in the plugin, so I could just grab it!
To wire this up, we just need to tell spring about it. That deviceResolver reference is from the spring-mobile plugin. (So make sure you don’t uninstall it.)
And my config….
This works great. If a mobile user logs in, they are always directed to the mobile landing page. And best of all it is easily configurable. I don’t have to dig through a bunch of code looking for if checks / flags / custom routing logic to change where I want logged in users to go.
The Login Page Switch-a-roo
I still was using the spring-mobile plugin’s ‘withMobileDevice()’ dynamic method, which I wasn’t fond of. I wanted a solution that worked, but you didn’t have to remember to switch out a view in the individual controller actions. I then remembered that Spring Security lets you configure your loginFormUrl in a very similar way to how they do the defaultTargetUrl. So I ripped out the spring-mobile changes to my login rendering action. I found that the step where this happens in the chain (AuthenticationEntryPoint), and created my own version.
And again my wiring and config, very similar to before.
And there ya go! All in only a few lines of code. If you know of a better way to acheive this, please to let me know, but I think this implementation is fairly clean and straight-forward. This solution should also work with just a standard Spring / Spring Security application. Apart from the configuration builder that grails offers (instead of XML) nothing is grails specific.