Things To Take Into Consideration
Before creating a customized user, we need to remind what a user is in Spring. We know from here that a user is an implementation of the UserDetails interface. Spring security also requires a loading mechanism, as an implementation of the UserDetailsService interface. To keep this example simple, we are not going to implement login/logout or other security features.The UserDetails interface is a bit incomplete in order to define a user in a real application. It defines getters and no setters. It is not a big deal, but the real pain is that the username (a string) is considered as 'the' key. Most software developers will prefer a long id.
To solve these issues, we define a PracticalUser interface:
public interface PracticalUserDetails extends UserDetails, CredentialsContainer { long getId(); void setPassword(String password); void setAccountExpired(boolean b); void setAccountLocked(boolean b); void setCredentialsExpired(boolean b); void setEnabled(boolean b); void setAuthorities( Collection<? extends GrantedAuthority> authorities); }
The UserDetailsService interface does not provide a get user per name or id, which is necessary for an administrator (for example). More, it does not allow to retrieve all existing users' id and name, or to update or insert users, or even to delete them.
Therefore, we create a PracticalUserDetailsService interface to solve these issues:
public interface PracticalUserDetailsService extends UserDetailsService { Set<PracticalUserDetailsDAO.UserIdentifiers> getUsers(); void deleteUser(long id); void upsertUser(PracticalUserDetails user); PracticalUserDetails getUser(long id); PracticalUserDetails getUser(String username); }
In-Memory DAO
To keep this example simple, we define a simple PracticalUserDetailsDAO:public interface PracticalUserDetailsDAO<U extends PracticalUserDetails> { void create(U user); boolean contains(U user); U read(String username); U read(long id); void update(U user); void delete(String username); void delete(long id); interface UserIdentifiers { long getId(); String getUsername(); } Set<UserIdentifiers> getUsers(); }
In a real implementation, using a JPA Repository is more appropriate.
Configuration
In the security.xml file, we define our practical user detail service (it will be registered in the authentication manager) and the in-memory DAO bean:<beans:beans xmlns="http://www.springframework.org/schema/security" xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd"> <http auto-config="true"> </http> <authentication-manager alias="authenticationManager"> <authentication-provider user-service-ref='practicalUserDetailsServiceInMemory' /> </authentication-manager> <beans:bean id="pud" class="com.jverstry.DAO.PracticalUserDetailsDAOInMemory"> </beans:bean> </beans:beans>
The JSP Pages
We use two pages. The main page displays registered users (together with a delete link) and registration form:The second page is displayed when the Create User button is clicked to check the name and the password:
The Controller
The controller is used to check the username and password:@Controller public class MyController { @Autowired private PracticalUserDetailsServiceInMemory pudm; @RequestMapping(value = "/") public ModelAndView index() { ModelAndView result = new ModelAndView("index"); result.addObject("users", this.pudm.getUsers()); return result; } @RequestMapping(value = "/delete/{id}") public String delete(@PathVariable(value="id") String id) { this.pudm.deleteUser(Long.parseLong(id)); return "redirect:/"; } @RequestMapping(value = "/create") @SuppressWarnings("AssignmentToMethodParameter") public ModelAndView add( @RequestParam(value="name") String name, @RequestParam(value="password") String password) { name = StringUtils.replace(name, " ", ""); password = StringUtils.replace(password, " ", ""); String errorMsg = ""; if ( name.length() == 0 ) { errorMsg += "Name is empty "; } if ( password.length() == 0 ) { errorMsg += "Password is empty "; } if ( errorMsg.isEmpty() ) { this.pudm.upsertUser(new PracticalUserDetailsImpl(name, password)); } ModelAndView result = new ModelAndView("create"); result.addObject("errorMsg", errorMsg); result.addObject("username", name); return result; } }
Running The Example
One can run it using the maven tomcat:run goal. Then, browse:http://localhost:9191/spring-mvc-customized-user/
More Spring related posts here.
No comments:
Post a Comment