【Spring Boot】配置 Spring Security

1.继承 WebSecurityConfigurerAdapter

通过重写抽象接口 WebSecurityConfigurerAdapter,再加上注解 @EnableWebSecurity,可以实现 Web 的安全配置。

WebSecurityConfigurerAdapterConfig 模块一共有 3 个 builder(构造程序)。

  • AuthenticationManagerBuilder:认证相关 builder,用来配置全局的认证相关的信息。它包含 AuthenticationProviderUserDetailsService,前者是 认证服务提供者,后者是 用户详情查询服务
  • WebSecurity:进行全局请求忽略规则配置、HttpFirewall 配置、debug 配置、全局 SecurityFilterChain 配置。
  • HttpSecurity:进行权限控制规则相关配置。

配置安全,通常要重写以下方法:

// 通过 auth 对象的方法添加身份验证
protected void configure(AuthenticationManagerBuilder auth) throws Exception {}
// 通常用于设置忽略权限的静态资源
public void configure(WebSecurity web) throws Exception {}
// 通过 HTTP 对象的 authorizeRequests() 方法定义 URL 访问权限。默认为 formLogin() 提供一个简单的登录验证页面
protected void configure(HttpSecurity httpSecurity) throws Exception {}

2.配置自定义策略

配置安全需要继承 WebSecurityConfigurerAdapter,然后重写其方法,见以下代码:

package com.example.demo.config;
 
// 指定为配置类
@Configuration
// 指定为 Spring Security 配置类,如果是 WebFlux,则需要启用@EnableWebFluxSecurity 
@EnableWebSecurity
// 如果要启用方法安全设置,则开启此项。
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  public void configure(WebSecurity web) throws Exception {
    //不拦截静态资源
    web.ignoring().antMatchers("/static/**");
  }
  
  @Bean
  public PasswordEncoder passwordEncoder() {
    // 使用 BCrypt 加密
    return new BCryptPasswordEncoder();
  }
  
  @Override
  protected void configure(HttpSecurity http) throws Exception { 
  	http.formLogin()
  			.usernameParameter("uname").passwordParameter("pwd").loginPage("/admin/login").permitAll()
				.and()
			.authorizeRequests()
				.antMatchers("/admin/**").hasRole("ADMIN")
				// 除上面外的所有请求全部需要鉴权认证
				.anyRequest().authenticated();
    http.logout().permitAll();
    http.rememberMe().rememberMeParameter("rememberme");
    // 处理异常,拒绝访问就重定向到 403 页面 
    http.exceptionHandling().accessDeniedPage("/403");
    http.logout().logoutSuccessUrl("/");
    http.csrf().ignoringAntMatchers("/admin/upload");
  }
}
  • formLogin():自定义用户登录验证的页面。表示开启表单登录配置,loginPage 用来配置登录页面地址;usernameParameter 表示登录用户名的参数名称;passwordParameter 表示登录密码的参数名称;permitAll 表示跟登录相关的页面和接口不做拦截,直接通过。需要注意的是 usernameParameterpasswordParameter 需要和 login.html 中登录表单的配置一致。
  • authorizeRequests():定义哪些 URL 需要被保护,哪些不需要被保护。
  • antMatchers("/admin/**").hasRole("ADMIN"):定义 /admin/ 下的所有 URL。只有拥有 ADMIN 角色的用户才有访问权限。
  • .logout().permitAll():表示在 Spring Security 配置中,‌无论用户是否经过身份验证,‌都可以访问注销(‌logout)‌页面。‌这意味着,‌即使是一个未经过身份验证的用户也可以访问注销功能,‌这在某些情况下可能是一个安全隐患。‌因此,‌这个配置通常用于开发环境或测试环境,‌以确保用户可以轻松地测试注销功能,‌而在生产环境中,‌出于安全考虑,‌通常会更加限制对注销页面的访问权限。‌
  • http.csrf():配置是否开启 CSRF 保护,还可以在开启之后指定忽略的接口。
  • and():会返回 HttpSecurityBuilder 对象的一个子类(实际上就是 HttpSecurity),所以 and() 方法相当于又回到 HttpSecurity 实例,重新开启新一轮的配置。在 Spring Security 的配置中,‌.and() 方法用于将多个安全配置连接起来,‌形成一个连续的配置链。‌这种方法允许开发者逐步添加和配置安全策略,‌确保每个配置步骤都是基于前一个步骤的结果进行的。‌通过使用 .and() 方法,‌可以构建复杂的安全配置,‌包括身份验证、‌授权、‌安全防护等。‌例如,‌在配置 Spring Security 时,‌可能会先设置用户认证方式,‌然后使用 .and() 方法连接到授权配置,‌接着可能再次使用 .and() 方法连接到 CSRF 保护等高级配置。‌这种链式配置方式使得代码更加清晰和易于管理。‌
http
    .someConfigurer
        .<some feature of configurer>()
        .<some feature of configurer>()
        .and()
    .someOtherConfigurer
        .<some feature of someOtherConfigurer>()
        ...
        .and()
     ...

如果开启了 CSRF,则一定在验证页面加入以下代码以传递 token 值:

<head>
  <meta name="_csrf" th:content="${_csrf.token}"/>
  <!-- default header name is X-CSRF-TOKEN -->
  <meta name="_csrf_header" th:content="${_csrf.headerName}"/>
</head>

如果要提交表单,则需要在表单中添加以下代码以提交 token 值:

<input type="hidden" th:name="${_csrf.parameterName)" th:value="${_csrf.token)">
  • http.rememberMe():“记住我” 功能,可以指定参数。
<input class="i-checks" type="checkbox" name="rememberme"/>&nbsp;&nbsp;记住我

3.配置加密方式

默认的加密方式是 BCrypt。只要在安全配置类配置即可使用,见以下代码:

@Bean
public PasswordEncoder passwordEncoder() {
	// 使用 BCrypt 加密
  return new BCryptPasswordEncoder();
}

在业务代码中,可以用以下方式对密码迸行加密:

BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
String encodePassword = encoder.encode(password);

3.1 BCrypt 加密

BCrypt 是一种基于哈希函数的加密算法,它使用一个 密码 和一个 盐值 作为输入,生成一个固定长度的 密码哈希值。这个哈希值在每次密码输入时都会重新生成,而且会随着盐值的改变而改变。BCrypt 的盐值是一个随机生成的字符串,与密码一起用于哈希函数中,使得相同的密码在每次加密时都会生成不同的哈希值。

在这里插入图片描述
BCrypt 的另一个重要特点是它使用了一个加密算法来混淆密码哈希值。这个加密算法使用一个密钥和一个初始化向量(IV)来加密密码和盐值。加密后的数据被存储在数据库中,用于后续的密码验证。

BCrypt 的加密过程可以分为以下几个步骤:

  • 生成盐值:BCrypt 使用一个随机数生成器生成一个随机的 盐值。这个盐值是一个随机的字符串,用于与密码一起生成哈希值。
  • 混合盐值和密码:将 密码盐值 混合在一起,然后使用一个 哈希函数 生成一个固定长度的 哈希值
  • 加密哈希值:使用一个 加密算法 将哈希值混淆,生成一个 加密的哈希值。这个加密的哈希值被存储在数据库中。
  • 验证密码:在验证密码时,用户输入 密码,系统使用相同的 盐值哈希函数加密算法 生成一个 新的哈希值。然后,将新的哈希值与数据库中的加密哈希值进行比较,如果它们匹配,则密码验证成功。

在这里插入图片描述
🚀 BCrypt 加密/匹配工具 - 在线密码哈希生成与匹配

在这里插入图片描述

4.自定义加密规则

除默认的加密规则,还可以自定义加密规则。具体见以下代码:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception ( 
	auth.userDetailsService(UserService()).passwordEncoder(new PasswordEncoder() { 
		@Override
		public String encode(CharSequence charSequence) {
			return MD5Util.encode((String) charSequence);
		}
		@Override
		public boolean matches(CharSequence charSequence, String s) {
			return s.equals(MD5Util.encode((String) charSequence));
		}
  });
}

5.配置多用户系统

一个完整的系统一般包含多种用户系统,比如 “后台管理系统 + 前端用户系统"。Spring Security 默认只提供一个用户系统,所以,需要通过配置以实现多用户系统。

比如,如果要构建一个前台会员系统,则可以通过以下步骤来实现。

5.1 构建 UserDetailsService 用户信息服务接口

构建前端用户 UserSecurityService 类,并继承 UserDetailsService。具体见以下代码:

public class UserSecurityService implements UserDetailsService {
	@Autowired
	private UserRepository userRepository;
	@Override
	public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
		User user = userRepository.findByName(name);
		if (user == null) {
			User mobileUser = userRepository.findByMobile(name);
			if (mobileUser == null) {
				User emailUser = userRepository .findByEmail(name);
				if (emailUser == null) {
					throw new UsernameNotFoundException("用户名,邮箱或手机号不存在!");
				} else {
					user = userRepository.findByEmail(name);
				}
			} else {
				user = userRepository.findByMobile(name);
			}
		} else if ("locked".equals(user.getStatus())) {
			//被锁定,无法登录
			throw new LockedException("用户被锁定”);
		}
		return user;
	}
}

5.2 进行安全配置

在继承 WebSecurityConfigurerAdapter 的 Spring Security 配置类中,配置 UserSecurityService 类。

@Bean
UserDetailsService UserService() {
	return new UserSecurityService();
}

如果要加入后台管理系统,则只需要重复上面步骤即可。

6.获取当前登录用户信息的几种方式

获取当前登录用户的信息,在权限开发过程中经常会遇到。而对新人来说,不太了解怎么获取,经常遇到获取不到或报错的问题。

所以,本节讲解如何在常用地方获取当前用户信息。

6.1 在 Thymeleaf 视图中获取

要 Thymeleaf 视图中获取用户信息,可以使用 Spring Security 的标签特性。

在 Thymeleaf 页面中引入 Thymeleaf 的 Spring Security 依赖,见以下代码:

<!DOCTYPE html>
<html lang="zh" xmlns:th=”http://www.thymeleaf.org" 
	xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
	<!-- 省略 -->
	<body>
		<!-- 匿名 -->
		<div sec:authorize="isAnonymous()">
			未登录,单击 <a th:href="@{/home/login}">登录</a>
		</div>
		<!-- 已登录 -->
		<div sec:authorize="isAuthenticated()">
			<p>已登录</p>
			<p>登录名: <span sec:authentication="name"></span></p>
			<p>角色: <span sec:authentication="principal.authorities"></span></p>
			<p>id: <span sec:authentication="principal.id"></span></p>
			<p>Username: <span sec:authentication="principal.username"></span></p>
		</div>
	</body>
</html>

这里要特别注意版本的对应。如果引入了 thymeleaf-extras-springsecurity 依赖依然获取不到信息,那么可能是 Thymeleaf 版本和 thymeleaf-extras-springsecurity 的版本不对。

请检查在 pom.xml 文件的两个依赖,见以下代码:

<dependency>
  <groupld>org.springframework.boot</groupld> 
  <artifactld>spring-boot-starter-thymeleaf</artifactld>
</dependency>

<dependency>
  <groupld>org.thymeleaf.extras</groupld>
  <artifactld>thymeleaf-extras-springsecurity5</artifactld>
</dependency>

6.2 在 Controller 中获取

在控制器中获取用户信息有 3 种方式,见下面的代码注释。

@GetMapping("userinfo")
public String getProduct(Principal principal, Authentication authentication, HttpServletRequest httpServletRequest) {
  /**
   * Description: 1.通过 Principal 参数获取
  */
  String username = principal.getName();
  /**
   * Description: 2.通过 Authentication 参数获取
   */
  String userName2 = authentication.getName();
  /**
   * Description: 3.通过 HttpServletRequest 获取
   */
  Principal httpServletRequestUserPrincipal = httpServletRequest.getUserPrincipal();
  String userName3 = httpServletRequestUserPrincipal.getName();
  return username;
}

6.3 在 Bean 中获取

在 Bean 中,可以通过以下代码获取:

Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
if (!(authentication instanceof AnonymousAuthenticationToken)) {
	String username = authentication.getName();
  return username;
}

在其他 Authentication 类也可以这样获取。比如在 UsernamePasswordAuthenticationToken 类中。

如果上面代码获取不到,并不是代码错误,则可能是因为以下原因造成的:

  • ⭕ 要使上面的获取生效,必须在继承 WebSecurityConfigurerAdapter 的类中的 http.antMatcher("/*") 的鉴权 URI 范围内。
  • ⭕ 没有添加 Thymeleaf 的 thymeleaf-extras-springsecurity 依赖。
  • ⭕ 添加了 Spring Security 的依赖,但是版本不对,比如 Spring Security 和 Thymeleaf 的版本不对。
《Vue和SpringBoot打造假日旅社管理系统》课程,将讲解如何使用Vue和SpringBoot开发这个项目,手把手演示开发流程!附赠源码、文档、数据库脚本等全部资料,提供售后答疑。 课程简介本课程讲解的是《基于 Vue 和 SpringBoot 的假日旅社管理系统》,该系统支持民宿档案、民宿新闻、民宿预定、民宿评论这四大核心业务,适用于乡村民宿企业的民宿预定业务。系统给每个民宿档案提供一个唯一标识,对民宿预定、评论等各个环节进行快速批量的数据采集,确保游客及时掌握景区民宿的真实数据,方便游客进行民宿预定。另外系统还包括员工管理、组织机构管理、文件管理、权限管理功能,给旅社企业提供更个性化的民宿管理模式。假日旅社管理系统采用了基于角色的访问控制,角色和菜单关联,一个角色可以配置多个菜单权限;然后再将用户和角色关联,一位用户可以赋予多个角色。这样用户就可以根据角色拿到该有的菜单权限,更方便旅社企业的管理人员进行权限管控。   软件技术选型前端Vue:Vue 是构建前端界面的核心框架,本系统采用 2.6.14 版本。View UI:基于 Vue.js2.0 的组件库,本系统采用 4.7.0 版本。后端Spring Boot:构建系统核心逻辑的后端框架,本系统采用 2.7.0 版本。MyBatis / MyBatis Plus:后端连接数据库的框架,本系统采用 3.5.2 版本。数据库MySQL:本项目的主数据库,本系统采用 8.0.29 版本。Redis:本系统采用基于 Windows 版本的 Redis,用于图形验证码和用户菜单权限的临时存储,采用了 5.0.14 版本。开发环境VsCode:项目前端的开发工具,使用版本为 1.68.0。IntelliJ IDEA :项目后端的开发工具,使用版本为 2021.3.2。Jdk:Java 的开发环境,使用版本为 17.0.3.1。Maven:后端项目的打包工具,使用版本为 3.6.2。NodeJs:前端项目的开发环境,使用版本为 16.13.0。 软件架构分析基于 Vue 和 SpringBoot 的假日旅社管理系统包括了系统基础模块、民宿档案模块、民宿新闻模块、民宿预定模块、民宿评论模块这五大功能模块,其架构如下图所示。  接下来,分别对五大模块进行详细介绍。系统基础模块系统基础模块,是用于支撑假日旅社管理系统的正常运行,这个模块包括了登陆注册模块、员工部门管理、菜单权限管理等。假日旅社管理系统支持用户使用账号、密码和图形验证码登陆,操作界面如下图所示。  假日旅社管理系统支持用户使用手机号、姓名、密码和图形验证码注册,操作界面如下图所示。 用户成功进入系统后,可进入到基于 Vue 和 SpringBoot 的假日旅社管理系统的首页,首页展示了当前登陆的地址、现在的时间和用户配置的常用模块,如下图所示。 接着用户点击左侧的用户管理,即可进入用户管理模块,用户管理模块的首页如下图所示。 用户可以在这个模块对系统登陆用户的档案进行维护,包括添加新用户、删除用户、编辑用户、根据姓名/部门查询用户。用户可以进入部门管理模块,管理旅社的部门数据,如下图所示。 同理用户可以进入到菜单管理模块,对系统的菜单进行管理,菜单管理模块的操作界面如下图所示。 民宿档案模块第二个模块是民宿档案模块,民宿档案就是用来管理民宿的数据,民宿档案包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿档案模块的主界面。用户可以点击顶部的“新增”按钮,进入民宿档案添加界面,添加民宿档案数据,如下图所示。 其中房间类型为下拉框单项选择,如下图所示。还有早餐情况也是下拉单选,如下图所示。 用户可以对现有的民宿档案数据进行编辑更新,只需点击每一行民宿档案数据的“编辑”按钮,即可进入民宿档案数据的编辑界面,如下图所示。 用户也可以对不需要的民宿数据进行删除操作,用户点击删除时,系统会弹出二次确认弹框,如下图所示。  民宿新闻模块第三个模块是民宿新闻模块,民宿新闻就是用来管理民宿的新闻资讯,包含的功能如下所示。 民宿新闻包括民宿的名称、面积、房号、房间类型、早餐情况、价格、备注等,以下是民宿新闻模块的主界面,其中的图片仅供测试样例使用。用户可以点击顶部的“新增”按钮,进入民宿新闻添加界面,添加民宿新闻数据,如下图所示。 新闻描述字段采用了 ueditor 富文本编辑器,这是由百度 web 前端研发部开发的所见即所得的开源富文本编辑器,具有轻量、可定制、用户体验优秀等特点,基于 MIT 开源协议,所有源代码可自由修改和使用。 用户可以对现有的民宿新闻数据进行编辑更新,只需点击每一行民宿新闻数据的“编辑”按钮,即可进入民宿新闻数据的编辑界面,如下图所示。 民宿预定模块第四个模块是民宿预定模块,旅客可以在民宿预定模块中预定民宿,达到旅客的住宿目的,民宿预定模块包含的功能如下所示。民宿预定包括了预定民宿 ID、预定民宿名称、预定日期、下单时间、下单人 ID、下单人姓名、价格、是否付款、下单备注等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个预约按钮,如下图所示。 如用户点击 1 幢 102 民宿的预约按钮后,会弹出预约确认框,需要输入预约的日期,日期表单默认选择今日,如下图所示。 旅客需要点击“确认预约”按钮,完成预约操作,系统给与“预约成功”提示,如下图所示。 预约成功后,旅客可以从民宿预定模块中进行查询,如下图所示。 最后旅客进行付款操作,点击每一行右侧的付款按钮,如下图所示。支付完成后,系统将预定单的支付状态改为付款,预定流程结束,如下图所示。 民宿评论模块 第五个模块是民宿预定模块,旅客可以在民宿预定结束后评论民宿,以帮助更多的人了解民宿,民宿评论模块包含的功能如下所示。 民宿评论包括了民宿名称、民宿 ID、评论时间、评论内容、评论人 ID、评论人姓名等字段,旅客首先进入民宿档案模块,可以看到每一行民宿数据都有一个评论按钮,如下图所示。 旅客点击评论后,系统给与弹框反馈,如下图所示。  用户输入评论内容后,点击确认评论按钮,即可完成评论操作,如下图所示。  旅客评论后,即可在民宿评论模块中查看此评论数据,如下图所示。 也可以在民宿模块中,双击民宿数据查看评论信息,如下图所示。 项目总结本软件是基于 Vue 和 SpringBoot 的假日旅社管理系统,包含了民宿档案、民宿新闻、民宿预定、民宿评论这四个功能模块。 开发本系统的目的,就是为了帮助旅游景点的民宿企业提高民宿管理效率,降低人力成本,让旅游景点的民宿企业获得更多的经济效益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

大数据与AI实验室

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值