Hướng dẫn sử dụng Spring Security với Spring MVC 5

Hướng dẫn sử dụng Spring Security với Spring MVC 5

huong-dan-su-dung-spring-security-voi-spring-mvc-5-2
Spring Framework

Hướng dẫn sử dụng Spring Security với Spring MVC 5

Hướng dẫn sử dụng Spring Security với Spring MVC 5 sẽ trình bày cách tạo một form login trong Spring MVC 5 với Spring Security.

Chúng tôi sẽ kết hợp với Project đã tạo ở bài Hướng dẫn xử lý database trong Spring MVC 5 với Spring Data JPA để xử lý tiếp.

Khi truy cập website, người dùng được yêu cầu đăng nhập trước khi thực hiện xem hoặc thêm một khách hàng

Hướng dẫn sử dụng Spring Security với Spring MVC 5 – Các bước thực hiện

1/ Tạo một Maven Web Application Project

Các bạn có thể tạo mới một Project. Trong bài hướng dẫn này, chúng tôi sử dụng lại project của bài Hướng dẫn xử lý database trong Spring MVC 5 với Spring Data JPA

2/ Mở file pom.xml và thêm dependency

<!-- Spring Security -->
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-web</artifactId>
   <version>${spring.security.version}</version>
</dependency>
<dependency>
   <groupId>org.springframework.security</groupId>
   <artifactId>spring-security-config</artifactId>
   <version>${spring.security.version}</version>
</dependency>

3/ Tạo thêm 2 table của database demoDB

-- Bảng users
create table users(
	username varchar(50) not null primary key,
	password varchar(100) not null,
	enabled boolean not null
);
-- Bảng role
create table authorities (
	username varchar(50) not null,
	authority varchar(50) not null,
	constraint fk_authorities_users foreign key(username) references users(username)
);
create unique index ix_auth_username on authorities (username,authority);

Thêm thông tin đăng nhập vào database

-- Thông tin user (username là admin, password là admin@123
insert into users(username,password,enabled)
values('admin','$2a$10$hbxecwitQQ.dDT4JOFzQAulNySFwEpaFLw38jda6Td.Y/cOiRzDFu',true);
-- Role của user
insert into authorities(username,authority) values('admin','ROLE_ADMIN');

4/ Tạo một model là một Java class và đặt tên User

Nhập code cho User

5/ Tạo một model là một Java class và đặt tên Authorities

Nhập code cho Authorities

6/ Tạo một Repository là một Interface và đặt tên là UserRepository

Nhập code cho UserRepositoy

7/ Tạo một DTO là một Java class và đặt tên là UserDetailsDTO

Nhập code cho UserDetailsDTO

package vn.giasutinhoc.spring5mvc.jpa.dto;

import java.util.Collection;
import java.util.stream.Collectors;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import vn.giasutinhoc.spring5mvc.jpa.model.User;

public class UserDetailsDTO implements UserDetails {

	private User user;
	
        public UserDetailsDTO(User user) {
		this.user = user;
	}

	@Override
	public Collection<? extends GrantedAuthority> getAuthorities() {
		return user.getAuthorities().stream()
				.map(authority -> new SimpleGrantedAuthority(authority.getAuthority().toString()))
				.collect(Collectors.toList());
	}

	public User getUserDetails() {
		return user;
	}
	
	@Override
	public String getPassword() {		
		return user.getPassword();
	}

	@Override
	public String getUsername() {		
		return user.getUsername();
	}

	@Override
	public boolean isAccountNonExpired() {
		return true;
	}

	@Override
	public boolean isAccountNonLocked() {	
		return true;
	}

	@Override
	public boolean isCredentialsNonExpired() {
		return true;
	}

	@Override
	public boolean isEnabled() {
		return true;
	}

}

8/ Tạo một service là một Java class và đặt tên UserDetailsServiceImpl

Nhập code cho UserDetailsServiceImpl

9/ Cấu hình Spring Security

Tạo một Java class và đặt tên WebSecurityConfig

Nhập code cho WebSecurityConfig

package vn.giasutinhoc.spring5mvc.jpa.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

	@Autowired
	private UserDetailsService userDetailsService;

	@Bean
	public BCryptPasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	};

	@Bean
	public DaoAuthenticationProvider authenticationProvider() {
		DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
		authProvider.setUserDetailsService(userDetailsService);
		authProvider.setPasswordEncoder(passwordEncoder());
		return authProvider;
	}

	@Override
	protected void configure(AuthenticationManagerBuilder auth) {
		auth.authenticationProvider(authenticationProvider());
	}

	protected void configure(HttpSecurity http) throws Exception {

		http.authorizeRequests()
			.antMatchers("/customer/**").hasAnyRole("ADMIN", "USER")			
			.antMatchers("/user/**", "/resource/**").permitAll()
			.and().formLogin().loginPage("/user/login")
			.usernameParameter("username").passwordParameter("password")
			.loginProcessingUrl("/user/postLogin").permitAll()			
			.failureUrl("/user/loginFailed").and().logout().logoutUrl("/user/doLogout")
			.logoutSuccessUrl("/user/logout").permitAll()
			.and().csrf().disable();

	}
}

10/ Tạo tiếp một Java class và đặt tên SecurityWebApplicationInitializer

Nhập code cho SecurityWebApplicationInitializer

11/ Mở WebMvcConfig.java và bổ sung code

12/ Mở AppInitializer.java và thêm code

13/ Tạo một controller là một Java class và đặt tên UserController

Nhập code cho UserController

package vn.giasutinhoc.spring5mvc.jpa.controller;

import java.security.Principal;

import javax.servlet.http.HttpSession;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.servlet.ModelAndView;

import vn.giasutinhoc.spring5mvc.jpa.dto.UserDetailsDTO;
import vn.giasutinhoc.spring5mvc.jpa.model.User;

@SessionAttributes({ "currentUser" })
@Controller
@RequestMapping("user")
public class UserController {

	private static final Logger log = LoggerFactory.getLogger(UserController.class);

	/**
	 * This method handles login GET requests. If users is already logged-in and
	 * tries to goto login page again, will be redirected to list page.
	 */
	@GetMapping("login")
	public String loginPage(Principal principal) {
		return principal == null ? "login" : "redirect:/";
	}

	@PostMapping("postLogin")
	public void postLogin(Model model, HttpSession session) {
		log.info("postLogin()");
		// read principal out of security context and set it to session
		UsernamePasswordAuthenticationToken authentication = (UsernamePasswordAuthenticationToken) SecurityContextHolder
				.getContext().getAuthentication();

		validatePrinciple(authentication.getPrincipal());

		User loggedInUser = ((UserDetailsDTO) authentication.getPrincipal()).getUserDetails();
		model.addAttribute("currentUser", loggedInUser.getUsername());
		session.setAttribute("userId", loggedInUser.getUsername());

	}

	private void validatePrinciple(Object principal) {
		if (!(principal instanceof UserDetailsDTO)) {
			throw new IllegalArgumentException("Principal can not be null!");
		}
	}

	@RequestMapping(value = "loginFailed", method = RequestMethod.GET)
	public String loginError(Model model) {
		log.info("Login attempt failed");
		model.addAttribute("error", "true");
		return "login";
	}

	/**
	 * This method handles logout requests. Toggle the handlers if you are
	 * RememberMe functionality is useless in your app.
	 */
	@GetMapping("logout")
	public ModelAndView logoutPage(SessionStatus session) {
		SecurityContextHolder.getContext().setAuthentication(null);
		session.setComplete();

		return new ModelAndView("login");
	}

}

14/ Tạo một view là một JSP file và đặt tên login

Nhập code cho login.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8"
    pageEncoding="UTF-8"%>
<%@taglib uri="http://www.springframework.org/tags" prefix="spring"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Đăng nhập</title>
<link href="<c:url value="/resources/css/bootstrap.min.css" />"
 rel="stylesheet">
<%@ page isELIgnored="false"%>
<script src="<c:url value="/resources/js/jquery-1.11.1.min.js" />"></script>
<script src="<c:url value="/resources/js/bootstrap.min.js" />"></script>
</head>
<body>
<div class="container">
  <div class="col-md-12">
  <div class="panel panel-info">
    <div class="panel-heading">
     <div class="panel-title">
 		<legend>Vui lòng đăng nhập</legend>
        <c:if test="${not empty error}">
           <div class="alert alert-danger">
               <spring:message code="AbstractUserDetailsAuthenticationProvider.badCredentials"/>
               <br/>
           </div>
        </c:if>
	</div>
    </div>
    <div class="panel-body">
    <form action="postLogin" method="post">       
        <div class="form-group">
            <input class="form:input-large" placeholder="User Name"
                   name='username' type="text">
        </div>
        <div class="form-group">
            <input class=" form:input-large" placeholder="Password"
                   name='password' type="password" value="">
        </div>
        <input class="btn" type="submit" value="Đăng nhập">        
    </form>
    </div>
  </div>
</div>
</body>
</html>

15 Tạọ một messages.properties

Nhập code cho messages.properties

Hướng dẫn sử dụng Spring Security với Spring MVC 5 – Build, Deploy và Run

1/ Về cách build, deploy và run các bạn tham khảo bài Hướng dẫn tạo project sử dụng Spring MVC 5 với eclipse

2/ Kết quả khi truy cập http://localhost:8080/SpringMVC_JPA/user/login

Sai thông tin đăng nhập

Đúng thông tin đăng nhập với user là admin, password là admin@123

Alert: You are not allowed to copy content or view source !!