栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【Spring Boot】Spring Boot MVC Security Example | 网页安全验证

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【Spring Boot】Spring Boot MVC Security Example | 网页安全验证

文章目录
  • 演示工具版本
  • 项目结构
  • Maven
  • 使用 Thymeleaf 模板引擎
  • 使用静态内容
    • 使用 JS 和 CSS 文件
    • 使用自定义 favicon
  • 使用 application.properties 配置数据库
  • MySQL 表创建语句
  • Spring Boot MVC 配置
  • Spring Boot Security 配置
  • 自定义登录和注销页面
  • 自定义拒绝访问异常情况下的403错误页面
  • 创建 DAO
  • 创建 Service
  • 创建 Controller
  • 运行应用程序
    • 1. 使用Eclipse
    • 2. 使用Maven命令
    • 3. 使用可执行的JAR
  • 参考文献
  • 源码下载

本页将介绍Spring Boot MVC安全验证登录和注销+Thymeleaf+CSRF+MySQL数据库+JPA+Hibernate实例。

Spring Boot根据类路径中存在的JAR来配置Spring功能。要在Spring Boot MVC中创建视图,我们应该选择模板引擎,而不是JSP,因为对于JSP来说,嵌入式servlet容器有已知的限制。

在我们的例子中,我们将使用Spring Boot MVC和Thymeleaf模板引擎。

我们将使用Thymeleaf创建自定义的登录、注销和其他页面。

我们将使用数据库进行用户认证。对于Spring Security,我们将创建一个安全配置文件,在那里我们将配置自定义的登录、注销和异常处理配置。

当我们为Spring Security使用JavaConfig配置时,它默认启用CSRF保护。

如果在Spring Security应用程序中启用了CSRF保护,Thymeleaf将自动在表单中包含CSRF令牌。

Spring Boot的所有默认设置都可以通过application.properties文件进行修改,比如与Spring MVC、Spring Security、Thymleaf和数据库有关的设置。

为了完全控制Spring MVC、Spring Security和数据库配置,我们应该分别创建JavaConfig。

在我们的例子中,我们将为Spring Security创建一个JavaConfig。

我们将创建自定义的登录和注销表单,用户将使用数据库进行验证。

为了与数据库进行交互,我们将使用JPA和Hibernate。

数据源和Hibernate属性将被配置在application.properties文件中。

现在让我们一步一步地讨论完整的例子。

演示工具版本
  1. Java 8
  2. Spring Boot 1.5.3.RELEASE
  3. Maven 3.3
  4. MySQL 5.5
  5. Eclipse Mars
项目结构

Maven

pom.xml



	4.0.0
	com.concretepage
	spring-boot-demo
	0.0.1-SNAPSHOT
	jar
	spring-demo
	Spring Boot Demo Project
	
		org.springframework.boot
		spring-boot-starter-parent
		1.5.3.RELEASE
	
	
		1.8
	
	
		
		     org.springframework.boot
		     spring-boot-starter-web
		
		
		    org.springframework.boot
		    spring-boot-starter-security
				
	        
		    org.springframework.boot
		    spring-boot-starter-data-jpa
	        	
		
		    org.springframework.boot
		    spring-boot-starter-thymeleaf
			    
	        
		    mysql
		    mysql-connector-java
	        	 
    	        
                    org.springframework.boot
                    spring-boot-devtools
                    true
                 
	 
	
	   
	      
		org.springframework.boot
		spring-boot-maven-plugin
	      
	   
	
 
使用 Thymeleaf 模板引擎

为了提供动态HTML内容,Spring Boot更倾向于使用模板引擎,如FreeMarker、Groovy、Thymeleaf、Mustache。

要在Spring Boot MVC中创建视图,应避免使用JSP,因为在处理JSP时,嵌入式Servlet有一些已知的限制。

在我们的例子中,我们使用Thymeleaf模板引擎来创建视图。

要启用Thymeleaf,我们需要在构建文件中使用以下Spring Boot启动器。

spring-boot-starter-thymeleaf

如果Spring Boot安全系统启用了CSRF保护,Thymeleaf将在表单中自动包含CSRF标记。

现在,模板引擎的默认位置如下所示。

src/main/resources/templates 

这意味着我们将把Thymeleaf文件放在上述路径中。如果我们想改变Thymeleaf的默认模板引擎路径,我们需要在application.properties中配置以下Spring Boot属性。

spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html 

根据需要改变前缀和后缀。Spring使用ThymeleafAutoConfiguration来自动配置Thymeleaf。找到可以在application.properties中使用的属性,以改变Thymeleaf自动配置的设置。

spring.thymeleaf.cache: 启用模板缓存,默认值为true。

spring.thymeleaf.check-template: 在渲染前检查模板是否存在,默认为true。

spring.thymeleaf.check-template-location: 检查模板位置是否存在,默认值为true。

spring.thymeleaf.content-type: 配置内容类型,默认为text/html。

spring.thymeleaf.enabled: 启用MVC Thymeleaf视图解析。默认为true。

spring.thymeleaf.encoding: 配置模板编码。默认为UTF-8。

spring.thymeleaf.excluded-view-names: 配置应从解析中排除的视图名称(逗号分隔)。

spring.thymeleaf.mode: 配置模板模式。默认为HTML 5。

spring.thymeleaf.prefix: 在创建URL时,将前缀加到视图名称上。默认是classpath:/templates/。

spring.thymeleaf.suffix: 在URL创建中附加到视图名称的后缀。默认值为.html。

spring.thymeleaf.template-resolver-order: 模板解析器在链上的顺序。

spring.thymeleaf.view-names: 配置可以解析的视图名称(逗号分隔)。

使用静态内容

默认情况下,Spring Boot为静态资源使用类路径中的/static目录。

如果我们使用可执行的JAR来运行我们的项目,那么我们就不能把静态资源放在src/main/webapp路径下,因为当JAR被打包时,它将被大多数构建工具默默地忽略掉。

当我们只想把项目打包成WAR文件时,可以使用src/main/webapp这个路径。

默认情况下,静态资源被映射到; INSERT INTO `users` (`username`, `password`, `full_name`, `role`, `country`, `enabled`) VALUES ('mukesh', '$2a$10$N0eqNiuikWCy9ETQ1rdau.XEELcyEO7kukkfoiNISk/9F7gw6eB0W', 'Mukesh Sharma', 'ROLE_ADMIN', 'India', 1), ('tarun', '$2a$10$QifQnP.XqXDW0Lc4hSqEg.GhTqZHoN2Y52/hoWr4I5ePxK7D2Pi8q', 'Tarun Singh', 'ROLE_USER', 'India', 1);

密码是使用BCrypt加密方案。要用BCrypt加密方案对密码进行加密,如下所示。

Main.java

package com.concretepage;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
public class Main {
	public static void main(String[] args) {
		BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
		System.out.println(encoder.encode("m123"));
	}
}  

现在查找与示例中使用的MySQL表对应的java实体。

Article.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="articles")
public class Article implements Serializable { 
	private static final long serialVersionUID = 1L;
	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	@Column(name="article_id")
        private int articleId;  
	@Column(name="title")
        private String title;
	@Column(name="category")	
	private String category;
	public int getArticleId() {
		return articleId;
	}
	public void setArticleId(int articleId) {
		this.articleId = articleId;
	}
	public String getTitle() {
		return title;
	}
	public void setTitle(String title) {
		this.title = title;
	}
	public String getCategory() {
		return category;
	}
	public void setCategory(String category) {
		this.category = category;
	}
}  

UserInfo.java

package com.concretepage.entity;
import java.io.Serializable;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name="users")
public class UserInfo implements Serializable {
	private static final long serialVersionUID = 1L;
	@Id
	@Column(name="username")
	private String userName;
	@Column(name="password")
	private String password;
	@Column(name="role")	
	private String role;
	@Column(name="full_name")	
	private String fullName;
	@Column(name="country")	
	private String country;
	@Column(name="enabled")	
	private short enabled;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getRole() {
		return role;
	}
	public void setRole(String role) {
		this.role = role;
	}
	public String getFullName() {
		return fullName;
	}
	public void setFullName(String fullName) {
		this.fullName = fullName;
	}
	public String getCountry() {
		return country;
	}
	public void setCountry(String country) {
		this.country = country;
	}
	public short getEnabled() {
		return enabled;
	}
	public void setEnabled(short enabled) {
		this.enabled = enabled;
	}
} 
Spring Boot MVC 配置

为了启用Spring Boot MVC,我们需要在构建文件中使用以下启动器。

spring-boot-starter-web 

当Spring Boot扫描类路径中的Spring Web时,它会自动配置Spring Web MVC。

要改变任何配置,Spring Boot在application.properties中提供了需要配置的属性。

找到这些属性。

spring.mvc.async.request-timeout: 异步请求的超时时间,单位为毫秒。

spring.mvc.date-format: 要使用的日期格式。

spring.mvc.favicon.enabled: 它决定启用和禁用favicon。默认值为true。

spring.mvc.locale: 要使用的区域设置。

spring.mvc.media-types.*: 将文件扩展名映射到媒体类型,以便进行内容协商。

spring.mvc.servlet.load-on-startup: 它配置了Spring Web Services Servlet的启动优先级。默认值是-1。

spring.mvc.static-path-pattern: 它配置了静态资源的路径模式。

spring.mvc.view.prefix: 它为Spring视图(如JSP)配置前缀。

spring.mvc.view.suffix: 它配置视图后缀。

为了完全控制Spring MVC的配置,我们可以创建一个带有@Configuration和@EnableWebMvc注释的配置类。

要重写任何设置,我们需要扩展WebMvcConfigurerAdapter类。

Spring Boot Security 配置

为了配置Spring Boot Security,我们需要在构建文件中使用以下Spring Boot启动器。

spring-boot-starter-security 

默认情况下,我们得到的是内存中的认证,只有一个名为user的用户和一个随机的默认密码,我们会在控制台中打印出来。

我们可以通过配置application.properties中的security属性来改变默认设置。

找到其中的一些。
security.user.name: 它配置用户名。默认的用户是user。

security.user.password: 它配置密码。

security.user.role: 它配置了角色。默认的角色是USER。

security.enable-csrf: 它启用CSRF。默认值为false。

当我们想要完全控制Spring Security时,我们需要创建带有@Configuration和@EnableWebSecurity注释的java配置。

要覆盖任何设置,我们需要扩展WebSecurityConfigurerAdapter类。

为了保护一个方法,我们需要用@EnableGlobalMethodSecurity来注释我们的配置类。

现在找到我们例子中使用的security配置。

SecurityConfig.java

package com.concretepage.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Autowired
	private MyAppUserDetailsService myAppUserDetailsService;	
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
		.antMatchers("/app/secure/**").hasAnyRole("ADMIN","USER")
		.and().formLogin()  //login configuration
                .loginPage("/app/login")
                .loginProcessingUrl("/app-login")
                .usernameParameter("app_username")
                .passwordParameter("app_password")
                .defaultSuccessUrl("/app/secure/article-details")	
		.and().logout()    //logout configuration
		.logoutUrl("/app-logout") 
		.logoutSuccessUrl("/app/login")
		.and().exceptionHandling() //exception handling configuration
		.accessDeniedPage("/app/error");
	} 
        @Autowired
   	public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    	      BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
              auth.userDetailsService(myAppUserDetailsService).passwordEncoder(passwordEncoder);
	}
} 

在上述安全配置中,我们已经配置了自定义的登录、注销和异常处理。Spring Security JavaConfig默认启用CSRF保护。

通过使用@EnableWebSecurity注解,Thymeleaf在表单中自动包含CSRF令牌。对于密码编码,我们使用Spring BCryptPasswordEncoder类。

为了使用数据库对用户进行认证,我们需要实现UserDetailsService。

MyAppUserDetailsService.java

package com.concretepage.config;
import java.util.Arrays;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.concretepage.dao.IUserInfoDAO;
import com.concretepage.entity.UserInfo;
@Service
public class MyAppUserDetailsService implements UserDetailsService {
	@Autowired
	private IUserInfoDAO userInfoDAO;
	@Override
	public UserDetails loadUserByUsername(String userName)
			throws UsernameNotFoundException {
		UserInfo activeUserInfo = userInfoDAO.getActiveUser(userName);
		GrantedAuthority authority = new SimpleGrantedAuthority(activeUserInfo.getRole());
		UserDetails userDetails = (UserDetails)new User(activeUserInfo.getUserName(),
				activeUserInfo.getPassword(), Arrays.asList(authority));
		return userDetails;
	}
} 
自定义登录和注销页面

使用Thymeleaf模板引擎找到自定义的登录和注销页面。由于我们使用的是JavaConfig中配置的spring security,CSRF保护被默认启用。

在运行时,CSRF令牌将由Thymeleaf自动包含在表单中。

custom-login.html



    
         Spring Boot MVC Security using Thymeleaf 
        
    
    
        

Spring Boot MVC Security using Thymeleaf

Bad Credentials

User Name :

Password:

articles.html




      Spring Boot MVC Security using Thymeleaf
      


   

User Articles Details

Logged in user: [[${#httpServletRequest.remoteUser}]]

Id Title Category
自定义拒绝访问异常情况下的403错误页面

当用户试图访问一个安全的、没有授权给请求的用户角色的方法时,就会抛出拒绝访问的异常。我们已经创建了一个带有自定义错误信息的错误页面。

403.html




      Spring Boot MVC Security using Thymeleaf
      


   

Access Denied Exception

Logged in user: [[${#httpServletRequest.remoteUser}]]

Error

创建 DAO

找到我们例子中使用的DAO接口和类。

IUserInfoDAO.java

package com.concretepage.dao;
import java.util.List;
import com.concretepage.entity.Article;
import com.concretepage.entity.UserInfo;
public interface IUserInfoDAO {
	UserInfo getActiveUser(String userName);
	List
getAllUserArticles(); }

UserInfoDAO.java

package com.concretepage.dao;
import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
import com.concretepage.entity.Article;
import com.concretepage.entity.UserInfo;
@Repository
@Transactional
public class UserInfoDAO implements IUserInfoDAO {
	@PersistenceContext	
	private EntityManager entityManager;
	public UserInfo getActiveUser(String userName) {
		UserInfo activeUserInfo = new UserInfo();
		short enabled = 1;
		List list = entityManager.createQuery("SELECt u FROM UserInfo u WHERe userName=? and enabled=?")
				.setParameter(1, userName).setParameter(2, enabled).getResultList();
		if(!list.isEmpty()) {
			activeUserInfo = (UserInfo)list.get(0);
		}
		return activeUserInfo;
	}
	@SuppressWarnings("unchecked")
	@Override
	public List
getAllUserArticles() { String hql = "FROM Article as atcl ORDER BY atcl.articleId"; return (List
) entityManager.createQuery(hql).getResultList(); } }
创建 Service

我们已经在我们的服务类中创建了一个安全的方法,可以由具有ADMIN角色的用户访问。找到我们例子中使用的服务接口和类。

IUserInfoService.java

package com.concretepage.service;
import java.util.List;
import org.springframework.security.access.annotation.Secured;
import com.concretepage.entity.Article;
public interface IUserInfoService {
     @Secured ({"ROLE_ADMIN"})
     List
getAllUserArticles(); }

UserInfoService.java

package com.concretepage.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.concretepage.dao.IUserInfoDAO;
import com.concretepage.entity.Article;
@Service
public class UserInfoService implements IUserInfoService {
	@Autowired
	private IUserInfoDAO userInfoDAO;
	@Override
	public List
getAllUserArticles(){ return userInfoDAO.getAllUserArticles(); } }
创建 Controller

找到我们例子中使用的控制器。

UserInfoController.java

package com.concretepage.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.servlet.ModelAndView;
import com.concretepage.service.IUserInfoService;
@Controller
@RequestMapping("app")
public class UserInfoController {
	@Autowired
	private IUserInfoService userInfoService;
	@GetMapping("login")
	public ModelAndView login() {
	    ModelAndView mav = new ModelAndView();
	    mav.setViewName("custom-login");
	    return mav;
        }	
	@GetMapping("secure/article-details")
	public ModelAndView getAllUserArticles() {
	    ModelAndView mav = new ModelAndView();
	    mav.addObject("userArticles", userInfoService.getAllUserArticles());
	    mav.setViewName("articles");
	    return mav;
        }
	@GetMapping("error")
	public ModelAndView error() {
	    ModelAndView mav = new ModelAndView();
	    String errorMessage= "You are not authorized for the requested data.";
	    mav.addObject("errorMsg", errorMessage);
	    mav.setViewName("403");
	    return mav;
        }		
} 
运行应用程序

要运行该应用程序,首先在MySQL中创建表,如例子中给出的。现在我们可以通过以下方式运行REST网络服务。

1. 使用Eclipse

使用页面末尾的下载链接下载项目的源代码。

将该项目导入eclipse。

使用命令提示符,进入项目的根文件夹并运行。

mvn clean eclipse:eclipse 

然后在eclipse中刷新该项目。点击Run as -> Java Application来运行主类MyApplication。主类的内容如下。

MyApplication.java

package com.concretepage;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class MyApplication {  
	public static void main(String[] args) {
		SpringApplication.run(MyApplication.class, args);
        }       
} 

Tomcat服务器将被启动。

2. 使用Maven命令

下载项目的源代码。使用命令提示符进入项目的根文件夹并运行命令。

mvn spring-boot:run 

Tomcat服务器将被启动。

3. 使用可执行的JAR

使用命令提示符,转到项目的根文件夹并运行该命令。

mvn clean package 

我们将在目标文件夹中得到可执行的spring-boot-demo-0.0.1-SNAPSHOT.jar。以下列方式运行这个JAR。

java -jar target/spring-boot-demo-0.0.1-SNAPSHOT.jar 

Tomcat服务器将被启动。

现在访问下面给出的网址。

http://localhost:8080/app/login 

1. 访问结果如图所示
输入具有ADMIN角色的凭证mukesh/m123。

2. 成功后,如下图所示。

当我们点击注销按钮时,该页面会重定向到登录页面。

3. 现在使用具有USER角色的凭据tarun/t123登录应用程序。

我们将得到拒绝访问的页面,因为它试图访问没有授权给USER角色的安全服务方法。

4. 如果我们输入错误的凭证,我们将得到错误信息。

参考文献

【1】Securing a Web Application
【2】Spring Boot Reference Guide
【3】Spring Boot Security REST + JPA + Hibernate + MySQL CRUD Example
【4】Spring Boot MVC Security Example

源码下载

提取码:mao4

spring-boot-mvc-security-custom-login-and-logout-thymeleaf-csrf-mysql-database-jpa-hibernate-example.zip

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/331706.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号