In this tutorial we will
discuss the Spring Security with Spring Boot and also will see an example based
on Spring security with Spring Boot.
1. Spring security Overview
Spring
security is the highly customizable authentication and access-control
framework. This is the security module for securing spring applications. But,
this can also be used for non-spring based application with few extra
configurations to enable the security features. Spring Security is a framework
that focuses on providing both authentication and authorization to Java
applications.
§ “Authentication” is
the process of establishing a principal who they claim to be (a “principal”
generally means a user, device or some other system which can perform an action
in your application).
§ “Authorization”
refers to the process of deciding whether a principal is allowed to perform an
action within your application. To arrive at the point where an authorization
decision is needed, the identity of the principal has already been established
by the authentication process. These concepts are common, and not at all
specific to Spring Security.
2. Spring Security Modules
In
Spring Security 3.0, the codebase has been sub-divided into separate jars which
more clearly separate different functionality areas and third-party
dependencies. The following are the list of modules currently shipped by spring
security framework.
§ Core (spring-security-core.jar) – This module contains the APIs for
basic authentication and access-control related mechanism. This is mandatory
for ant spring security applications.
§ Remoting (spring-security-remoting.jar)
–
This module provides integration to the Spring Remoting. You don’t need to
include this module unless you are writing remote client applications.
§ Web (spring-security-web.jar) – This module contains APIs for servlet
filters and any web based authentication like access restriction for URLs. Any
web application would require this module.
§ Config (spring-security-config.jar) – Contains the security namespace parsing
code & Java configuration code. You need it if you are using the Spring
Security XML namespace for configuration. If you are not using XML
configurations, you can ignore this module.
§ LDAP (spring-security-ldap.jar)– Required if you need to use LDAP authentication
or manage LDAP user entries.
§ ACL (spring-security-acl.jar) – Specialized domain object ACL
implementation. Used to apply security to specific domain object instances
within your application.
§ CAS (spring-security-cas.jar) – Spring Security’s CAS client
integration. If you want to use Spring Security web authentication with a CAS
single sign-on server.
§ OpenID (pring-security-openid.jar) – OpenID web authentication support.
Used to authenticate users against an external OpenID server.
§ Test (spring-security-test.jar)– Support for testing with Spring
Security.
3. Getting Spring Security
You
can get hold of Spring Security in several ways.
3.1.
Usage with Maven
A
minimal Spring Security Maven set of dependencies typically looks like the
following:
Pom.xml
<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>
3.2.
Usage with Gradle
A
minimal Spring Security Gradle set of dependencies typically looks like the
following:
build.gradle
dependencies {
compile
'org.springframework.security:spring-security-web:4.1.2.RELEASE'
compile
'org.springframework.security:spring-security-config:4.1.2.RELEASE'
}
4. Core Components
Core
Components represent the building blocks of spring security and what are the
core components that are actually used while user is authenticating to your
application. So if you ever need to go beyond a simple namespace configuration
then it’s important that you understand what they are, even if you don’t
actually need to interact with them directly.
4.1
SecurityContext
As
the name implies, this interface is the corner stone of storing all the
security related details for your application. When you enable spring security
for your application, a SecurityContext will enable for each application and
stores the details of authenticated user, etc. It uses Authentication object
for storing the details related to authentications.
4.2
SecurityContextHolder
The
most fundamental object is SecurityContextHolder. This class is important for
accessing any value from the SecurityContext. This is where we store details of
the present security context of the application, which includes details of the
principal currently using the application. By default the SecurityContextHolder
uses a ThreadLocal to store these details, which means that the security
context is always available to methods in the same thread of execution, even if
the security context is not explicitly passed around as an argument to those
methods.
Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
String username =
((UserDetails)principal).getUsername();
} else {
String username = principal.toString();
}
4.3
Authentication
Let’s
consider a standard authentication scenario that everyone is familiar with.
1.
A user is prompted to log in with a username and password.
2.
The system verifies that the password
is correct for the username.
3.
The context information for that user
is obtained their list of roles and so on.
4.
A security context is established for
the user
5.
The user proceeds, potentially to
perform some operation which is potentially protected by an access control
mechanism which checks the required permissions for the operation against the
current security context information.
The
following are the steps to achieve the authentication:
1. Authentication is an interface which has several
implementations for different authentication models. For a simple user name and
password authentication, spring security would use UsernamePasswordAuthenticationToken.
When user enters username and password, system creates a new instance of UsernamePasswordAuthenticationToken.
2.
The token is passed to an instance of AuthenticationManager for validation. Internally what AuthenticationManager will do is to iterate the list of configured AuthenticationProvider to validate the request. There should be at
least one provider to be configured for the valid authentication.
3. The AuthenticationManager returns
a fully populated Authentication instance on successful authentication.
4. The final step is to establish a
security context by invoking SecurityContextHolder.getContext().setAuthentication(),
passing in the returned authentication object.
4.4
UserDetailsService
UserDetails
is a core interface in Spring Security. It represents a principal, but in an
extensible and application-specific way. Think of UserDetails as the adapter
between your own user database and what Spring Security needs inside the
SecurityContextHolder. UserDetailsService is a core interface in spring
security to load user specific data. This interface is considered as user DAO
and will be implemented by specific DAO implementations. For example, for a
basic in memory authentication, there is an InMemoryUserDetailsManager. This
interface declares only one method loadUserByUsername (String username) which
simplifies the implementation classes to write other specific methods.
Suppose
you want to use your existing DAO classes to load the user details from the
database, just implement the UserDetailsService and override the method
loadUserByUsername(String username). An example of this implementation would
look like this:
@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);
}
}
In
the above code, the model CurrentUser must of of type
org.springframework.security.userdetails.UserDetails. In the below example
application, I have extended the org.springframework.security.userdetails.UserDetails
class and written the custom user class. This will have the advantage of not
exposing our domain class.
4.5
GrantedAuthority
Apart
from authenticating to the application, another important component is to get
the list of granted authorities for the logged in user. This comes as part of
the authorization process. This is retrieved by calling the getAuthorities() in
Authentication object. This returns the list of GrantedAuthority which denotes
roles for the users. Such authorities are usually “roles”, such as
ROLE_ADMINISTRATOR orROLE_HR_SUPERVISOR. These roles are later on configured
for web authorization, method authorization and domain object authorization.
Summary
The major building blocks of Spring
Security that we’ve seen so far are:
§ SecurityContextHolder, to provide access to the SecurityContext.
§ SecurityContext,
to hold the Authentication and possibly request-specific security
information.
§ Authentication,
to represent the principal in a Spring Security-specific
manner.
§ GrantedAuthority,
to reflect the application-wide permissions granted to a principal.
§ UserDetails,
to provide the necessary information to build an Authentication object from
your application’s DAOs or other source of security data.
§ UserDetailsService, to create a UserDetails when passed in a
String-based username (or certificate ID or the like).
5. Spring Security Example Application
This section walks you through the
process of creating a simple web application in Spring Boot with resources that
are protected by Spring Security.
What you’ll build
You’ll build a Spring MVC application
that secures the page with a login form backed by a fixed list of users. Let’s
start with the use cases for every common web application with some basic access
restrictions. So, the requirements of such an app could be:
§ The app will have users, each with role Admin or User
§ They log in by their emails and passwords
§ Non-admin users can view their info, but cannot
peek at other users
§ Admin users can list and view all the users, and
create new ones as well
§ Customized form for login
§ “Remember me”
authentication for laziest
§ Possibility to logout
§ Home page will be available for everyone,
authenticated or not
Let’s create Web Project with Spring
Boot Web Initialzr with Spring Web, Spring Data JPA, Spring Security and H2 Database. So following project structure we have
after creating from web interface and adding necessary files for this example.
Let’s discuss files of this example.
Dependencies pom.xml
<?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.programingsoeasy.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>
WebSecurityConfigurerAdapter
This is the Java configuration class for writing the web based security configurations. You can override the methods in this class to configure the following things:
This is the Java configuration class for writing the web based security configurations. You can override the methods in this class to configure the following things:
§ Enforce the user to be authenticated prior to
accessing any URL in your application
§ Create a user with the username user , password,
and role of ROLE_USER
§ Enables HTTP Basic and Form based authentication
§ Spring Security will automatically render a login
page and logout success page for you
SecurityConfig.java
package com.programingsoeasy.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 Shailesh
*
*/
@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
User.java
User.java
package com.programingsoeasy.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.programingsoeasy.sbsecurity.role.Role;
/**
* @author Shailesh
*
*/
@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;
}
}
Role.java
package com.programingsoeasy.sbsecurity.role;
/**
* @author Shailesh
*
*/
public enum Role {
USER, ADMIN
}
Besides that, a form
for creating a new user will be nice to have:
UserBean.java
UserBean.java
package com.programingsoeasy.sbsecurity.bean;
import
javax.validation.constraints.NotNull;
import
org.hibernate.validator.constraints.NotEmpty;
import com.programingsoeasy.sbsecurity.role.Role;
/**
* @author Shailesh
*
*/
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.
CurrentUser.java
package com.programingsoeasy.sbsecurity.bean;
import org.springframework.security.core.authority.AuthorityUtils;
import com.programingsoeasy.sbsecurity.model.User;
import com.programingsoeasy.sbsecurity.role.Role;
/**
* @author Shailesh
*
*/
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();
}
}
Service Layer
In service layer, where the business logic should, we’d need something to retrieve the User by his id, email, list all the users and create a new one.
UserService .java
package com.programingsoeasy.sbsecurity.service;
import java.util.Collection;
import com.programingsoeasy.sbsecurity.bean.UserBean;
import com.programingsoeasy.sbsecurity.model.User;
/**
* @author Shailesh
*
*/
public interface UserService {
User getUserById(long id);
User getUserByEmail(String email);
Collection<User> getAllUsers();
User create(UserBean userBean);
}
UserServiceImpl .java
The implementation of the service:
The implementation of the service:
package com.programingsoeasy.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.programingsoeasy.sbsecurity.bean.UserBean;
import com.programingsoeasy.sbsecurity.model.User;
import com.programingsoeasy.sbsecurity.model.UserRepository;
/**
* @author Shailesh
*
*/
@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
This section explains the service classes and spring data repository implementation.
UserRepository .java
This section explains the service classes and spring data repository implementation.
UserRepository .java
package com.programingsoeasy.sbsecurity.model;
import
org.springframework.data.repository.CrudRepository;
/**
* @author Shailesh
*
*/
public interface UserRepository extends
CrudRepository<User, Long>{
User findOneByEmail(String email);
}
CurrentUserDetailsService.java
package com.programingsoeasy.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.programingsoeasy.sbsecurity.bean.CurrentUser;
import com.programingsoeasy.sbsecurity.model.User;
/**
* @author Shailesh
*
*/
@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
Home Page
Home Page
package com.programingsoeasy.sbsecurity.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import
org.springframework.stereotype.Controller;
import
org.springframework.web.bind.annotation.RequestMapping;
/**
* @author Shailesh
*
*/
@Controller
public class HomeController {
private static final Logger LOGGER =
LoggerFactory.getLogger(HomeController.class);
@RequestMapping("/")
public String getHomePage() {
LOGGER.debug("Getting home page");
return "home";
}
}
Login Page
package com.programingsoeasy.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 Shailesh
*
*/
@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.programingsoeasy.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.programingsoeasy.sbsecurity.bean.UserBean;
import com.programingsoeasy.sbsecurity.bean.validator.UserBeanValidator;
import com.programingsoeasy.sbsecurity.service.UserService;
/**
* @author Shailesh
*
*/
@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.programingsoeasy.sbsecurity.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import
org.springframework.stereotype.Service;
import com.programingsoeasy.sbsecurity.bean.CurrentUser;
import com.programingsoeasy.sbsecurity.role.Role;
/**
* @author Shailesh
*
*/
@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));
}
}
application.properties
#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.programingsoeasy=DEBUG
spring.freemarker.template-loader-path=/WEB-INF/ftl
spring.freemarker.expose-request-attributes=true
spring.freemarker.expose-spring-macro-helpers=true
Here we are using freemarker template
for views layers.
You can access this
whole running project from below link.
https://github.com/SpringBootSecurity
https://github.com/SpringBootSecurity
No comments:
Post a Comment