<dependencies> <!-- ... other dependency elements ... --> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-web</artifactId> <version>4.1.2.RELEASE</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>4.1.2.RELEASE</version> </dependency> </dependencies>
dependencies {
compile 'org.springframework.security:spring-security-web:4.1.2.RELEASE'
compile 'org.springframework.security:spring-security-config:4.1.2.RELEASE'
}
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username = ((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
@Service
public class CurrentUserDetailsService implements UserDetailsService {
private final UserService userService;
@Autowired
public CurrentUserDetailsService(UserService userService) {
this.userService = userService;
}
public CurrentUser loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userService.getUserByUsername(username);
return new CurrentUser(user);
}
}

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.dineshonjava.sbsecurity</groupId>
<artifactId>SpringBootSecurity</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>SpringBootSecurity</name>
<description>SpringBootSecurity project for Spring Boot and Spring Security</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.4.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
/**
*
*/
package com.dineshonjava.sbsecurity.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.security.SecurityProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* @author Dinesh.Rajput
*
*/
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter{
@Autowired
UserDetailsService userDetailsService;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home", "/public/**").permitAll()
.antMatchers("/users/**").hasAuthority("ADMIN")
.anyRequest().fullyAuthenticated()
.and()
.formLogin()
.loginPage("/login")
.failureUrl("/login?error")
.usernameParameter("email")
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
.logoutSuccessUrl("/")
.permitAll();
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(userDetailsService)
.passwordEncoder(new BCryptPasswordEncoder());
}
}
Domain Classes/**
*
*/
package com.dineshonjava.sbsecurity.model;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import com.dineshonjava.sbsecurity.role.Role;
/**
* @author Dinesh.Rajput
*
*/
@Entity
@Table(name = "user")
public class User implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "userid", nullable = false, updatable = false)
Long userid;
@Column(name = "username", nullable = false)
String username;
@Column(name = "email", nullable = false, unique = true)
String email;
@Column(name = "password", nullable = false)
String password;
@Column(name = "role", nullable = false)
@Enumerated(EnumType.STRING)
Role role;
public Long getUserid() {
return userid;
}
public void setUserid(Long userid) {
this.userid = userid;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
@Override
public String toString() {
return "User [userid=" + userid + ", username=" + username + ", email="
+ email + ", password=" + password + ", role=" + role + "]";
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((email == null) ? 0 : email.hashCode());
result = prime * result
+ ((password == null) ? 0 : password.hashCode());
result = prime * result + ((role == null) ? 0 : role.hashCode());
result = prime * result + ((userid == null) ? 0 : userid.hashCode());
result = prime * result
+ ((username == null) ? 0 : username.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
User other = (User) obj;
if (email == null) {
if (other.email != null)
return false;
} else if (!email.equals(other.email))
return false;
if (password == null) {
if (other.password != null)
return false;
} else if (!password.equals(other.password))
return false;
if (role != other.role)
return false;
if (userid == null) {
if (other.userid != null)
return false;
} else if (!userid.equals(other.userid))
return false;
if (username == null) {
if (other.username != null)
return false;
} else if (!username.equals(other.username))
return false;
return true;
}
}
/**
*
*/
package com.dineshonjava.sbsecurity.role;
/**
* @author Dinesh.Rajput
*
*/
public enum Role {
USER, ADMIN
}
/**
*
*/
package com.dineshonjava.sbsecurity.bean;
import javax.validation.constraints.NotNull;
import org.hibernate.validator.constraints.NotEmpty;
import com.dineshonjava.sbsecurity.role.Role;
/**
* @author Dinesh.Rajput
*
*/
public class UserBean {
@NotEmpty
private String username = "";
@NotEmpty
private String email = "";
@NotEmpty
private String password = "";
@NotEmpty
private String passwordRepeated = "";
@NotNull
private Role role = Role.USER;
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getPasswordRepeated() {
return passwordRepeated;
}
public void setPasswordRepeated(String passwordRepeated) {
this.passwordRepeated = passwordRepeated;
}
public Role getRole() {
return role;
}
public void setRole(Role role) {
this.role = role;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
This will function as a data transfer object (DTO) between the web layer and service layer. It's annotated by Hibernate Validator validation constraints and sets some sane defaults./**
*
*/
package com.dineshonjava.sbsecurity.bean;
import org.springframework.security.core.authority.AuthorityUtils;
import com.dineshonjava.sbsecurity.model.User;
import com.dineshonjava.sbsecurity.role.Role;
/**
* @author Dinesh.Rajput
*
*/
public class CurrentUser extends org.springframework.security.core.userdetails.User {
/**
*
*/
private static final long serialVersionUID = 1L;
private User user;
public CurrentUser(User user) {
super(user.getEmail(), user.getPassword(), AuthorityUtils.createAuthorityList(user.getRole().toString()));
this.user = user;
}
public User getUser() {
return user;
}
public Long getId() {
return user.getUserid();
}
public Role getRole() {
return user.getRole();
}
@Override
public String toString() {
return "CurrentUser{" +
"user=" + user +
"} " + super.toString();
}
}
/**
*
*/
package com.dineshonjava.sbsecurity.service;
import java.util.Collection;
import com.dineshonjava.sbsecurity.bean.UserBean;
import com.dineshonjava.sbsecurity.model.User;
/**
* @author Dinesh.Rajput
*
*/
public interface UserService {
User getUserById(long id);
User getUserByEmail(String email);
Collection<User> getAllUsers();
User create(UserBean userBean);
}
UserServiceImpl .java/**
*
*/
package com.dineshonjava.sbsecurity.service;
import java.util.Collection;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import com.dineshonjava.sbsecurity.bean.UserBean;
import com.dineshonjava.sbsecurity.model.User;
import com.dineshonjava.sbsecurity.model.UserRepository;
/**
* @author Dinesh.Rajput
*
*/
@Service
public class UserServiceImpl implements UserService {
private static final Logger LOGGER = LoggerFactory.getLogger(UserServiceImpl.class);
@Autowired
UserRepository userRepository;
@Override
public User getUserById(long id) {
LOGGER.debug("Getting user={}", id);
return userRepository.findOne(id);
}
@Override
public User getUserByEmail(String email) {
LOGGER.debug("Getting user by email={}", email.replaceFirst("@.*", "@***"));
return userRepository.findOneByEmail(email);
}
@Override
public Collection<User> getAllUsers() {
LOGGER.debug("Getting all users");
return (Collection<User>) userRepository.findAll();
}
@Override
public User create(UserBean userBean) {
User user = new User();
user.setUsername(userBean.getUsername());
user.setEmail(userBean.getEmail());
user.setPassword(new BCryptPasswordEncoder().encode(userBean.getPassword()));
user.setRole(userBean.getRole());
return userRepository.save(user);
}
}
Spring Data Repository/**
*
*/
package com.dineshonjava.sbsecurity.model;
import org.springframework.data.repository.CrudRepository;
/**
* @author Dinesh.Rajput
*
*/
public interface UserRepository extends CrudRepository<User, Long>{
User findOneByEmail(String email);
}
CurrentUserDetailsService.java/**
*
*/
package com.dineshonjava.sbsecurity.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.dineshonjava.sbsecurity.bean.CurrentUser;
import com.dineshonjava.sbsecurity.model.User;
/**
* @author Dinesh.Rajput
*
*/
@Service
public class CurrentUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(CurrentUserDetailsService.class);
@Autowired
UserService userService;
@Override
public UserDetails loadUserByUsername(String email)
throws UsernameNotFoundException {
LOGGER.debug("Authenticating user with email={}", email.replaceFirst("@.*", "@***"));
User user = userService.getUserByEmail(email);
return new CurrentUser(user);
}
}
Spring MVC Configurations Web Layer/**
*
*/
package com.dineshonjava.sbsecurity.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Dinesh.Rajput
*
*/
@Controller
public class HomeController {
private static final Logger LOGGER = LoggerFactory.getLogger(HomeController.class);
@RequestMapping("/")
public String getHomePage() {
LOGGER.debug("Getting home page");
return "home";
}
}
/**
*
*/
package com.dineshonjava.sbsecurity.controller;
import java.util.Optional;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.servlet.ModelAndView;
/**
* @author Dinesh.Rajput
*
*/
@Controller
public class LoginController {
private static final Logger LOGGER = LoggerFactory.getLogger(LoginController.class);
@RequestMapping(value = "/login", method = RequestMethod.GET)
public ModelAndView getLoginPage(@RequestParam Optional<String> error) {
LOGGER.debug("Getting login page, error={}", error);
return new ModelAndView("login", "error", error);
}
}
User Page/**
*
*/
package com.dineshonjava.sbsecurity.controller;
import javax.validation.Valid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.ModelAndView;
import com.dineshonjava.sbsecurity.bean.UserBean;
import com.dineshonjava.sbsecurity.bean.validator.UserBeanValidator;
import com.dineshonjava.sbsecurity.service.UserService;
/**
* @author Dinesh.Rajput
*
*/
@Controller
public class UserController {
private static final Logger LOGGER = LoggerFactory.getLogger(UserController.class);
@Autowired
UserService userService;
@Autowired
UserBeanValidator userBeanValidator;
@InitBinder("form")
public void initBinder(WebDataBinder binder) {
binder.addValidators(userBeanValidator);
}
@RequestMapping("/users")
public ModelAndView getUsersPage() {
LOGGER.debug("Getting users page");
return new ModelAndView("users", "users", userService.getAllUsers());
}
@PreAuthorize("@currentUserServiceImpl.canAccessUser(principal, #id)")
@RequestMapping("/user/{id}")
public ModelAndView getUserPage(@PathVariable Long id) {
LOGGER.debug("Getting user page for user={}", id);
return new ModelAndView("user", "user", userService.getUserById(id));
}
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.GET)
public ModelAndView getUserCreatePage() {
LOGGER.debug("Getting user create form");
return new ModelAndView("user_create", "form", new UserBean());
}
@PreAuthorize("hasAuthority('ADMIN')")
@RequestMapping(value = "/user/create", method = RequestMethod.POST)
public String handleUserCreateForm(@Valid @ModelAttribute("form") UserBean form, BindingResult bindingResult) {
LOGGER.debug("Processing user create form={}, bindingResult={}", form, bindingResult);
if (bindingResult.hasErrors()) {
return "user_create";
}
try {
userService.create(form);
} catch (DataIntegrityViolationException e) {
LOGGER.warn("Exception occurred when trying to save the user, assuming duplicate email", e);
bindingResult.reject("email.exists", "Email already exists");
return "user_create";
}
return "redirect:/users";
}
}
CurrentUserServiceImpl.java/**
*
*/
package com.dineshonjava.sbsecurity.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import com.dineshonjava.sbsecurity.bean.CurrentUser;
import com.dineshonjava.sbsecurity.role.Role;
/**
* @author Dinesh.Rajput
*
*/
@Service
public class CurrentUserServiceImpl implements CurrentUserService {
private static final Logger LOGGER = LoggerFactory.getLogger(CurrentUserDetailsService.class);
@Override
public boolean canAccessUser(CurrentUser currentUser, Long userId) {
LOGGER.debug("Checking if user={} has access to user={}", currentUser, userId);
return currentUser != null
&& (currentUser.getRole() == Role.ADMIN || currentUser.getId().equals(userId));
}
}
#security.user.name=root #security.user.password=111 #security.user.role=ADMIN logging.level.org.springframework=WARN logging.level.org.hibernate=WARN logging.level.com.dineshonjava=DEBUG spring.freemarker.template-loader-path=/WEB-INF/ftl spring.freemarker.expose-request-attributes=true spring.freemarker.expose-spring-macro-helpers=true
Labels: Spring Boot