23. springBoot高级篇——整合Security安全框架

        Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型。他可以实现强大的web安全控制。对于安全控制,我们仅需引入spring-boot-starter-security模块,进行少量的配置,即可实现强大的安全管理。

        应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。这两个主要区域是Spring Security 的两个目标,认证和授权的概念是通用的而不只在Spring Security中。

        “认证”(Authentication),是建立一个他声明的主体的过程(一个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动作的其他系统)。

        “授权”(Authorization)指确定一个主体是否允许在你的应用程序执行一个动作的过程。为了抵达需要授权的店,主体的身份已经有认证过程建立。

1. 添加认证授权步骤

1.1 引入Security依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

1.2 编写Security配置类

        查看spring官网,https://docs.spring.io/spring-security/site/docs/current/reference/html5/#samples

点击进入GitHub示例工程中,在工程中可以看到一个配置类SecurityConfig,我们将该类复制过来。

package com.bjc.security.config;

import org.springframework.context.annotation.Bean;
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.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests(authorize -> authorize
						.antMatchers("/css/**", "/index").permitAll()
						.antMatchers("/user/**").hasRole("USER")
				)
				.formLogin(formLogin -> formLogin
						.loginPage("/login")
						.failureUrl("/login-error")
				);
	}
	@Bean
	public UserDetailsService userDetailsService() {
		UserDetails userDetails = User.withDefaultPasswordEncoder()
				.username("user")
				.password("password")
				.roles("USER")
				.build();
		return new InMemoryUserDetailsManager(userDetails);
	}
}

1.2.1 配置类

        通过官网demo代码,可以知道该配置类需要继承WebSecurityConfigurerAdapter,并用注解@EnableWebSecurity标注,该注解被@Configuration标注了,所以我们不需要再该配置类上添加@Configuration注解。

1.2.2 安全登录控制请求访问权限

        根据官网demo,可以知道我们可以重写configure方法,通过该方法的参数http来定制安全规则

package com.bjc.security.config;

import org.springframework.context.annotation.Bean;
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.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(HttpSecurity http) throws Exception {
		// 定制请求授权规则
		http.authorizeRequests(authorize -> authorize
						.antMatchers("/","/css/**", "/index").permitAll()  // 访问首页、静态资源所有用户可以访问
						.antMatchers("/level1/**").hasRole("VIP1") 		// 配置访问level1下的所有资源需要角色VIP1的用户
						.antMatchers("/level2/**").hasRole("VIP2")
						.antMatchers("/level3/**").hasRole("VIP3")
				)
				.formLogin();   // 开启自动配置的登录功能  如果访问没有权限,就会跳转/login来到登录页面(security自带的)
	}

	/**
	 * 配置认证用户
	 * */
	@Override
	protected void configure(AuthenticationManagerBuilder auth) throws Exception {
		// 内存用户(写死的用户)
		auth.inMemoryAuthentication()
				.passwordEncoder(new PasswordEncoder() {
					@Override
					public String encode(CharSequence charSequence) {
						return charSequence.toString();
					}

					@Override
					public boolean matches(CharSequence charSequence, String s) {
						return s.equals(charSequence);
					}
				})
				.withUser("zhangsan")		// 用户名
				.password("123456")					// 密码
				.roles("VIP1","VIP2")				// 用户所属角色
				.and()								// 再添加一个
				.withUser("lisi")
				.password("123456")
				.roles("VIP2,VIP3")
				.and()
				.withUser("wangwu")
				.password("123456")
				.roles("VIP2","VIP3");
		// 通过数据库查询
		// auth.jdbcAuthentication()
	}
}

配置类写好之后,再次访问首页,点击资源如果没有登录会跳转到security内置的登录页面去进行登录。登录成功之后就可以访问对应的资源了,如果访问的资源没有权限,就会报错

注意:内存用户验证时,Spring boot 2.0.1引用的security 依赖是 spring security 5.X版本,此版本需要提供一个PasswordEncorder的实例,否则后台汇报错误:java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"并且页面毫无响应。

1.2.3 添加注销功能

        注销功能很简单,只需要开启注销功能,在配置类中添加http.logout();

然后在界面添加退出登录的form表单

<form th:action="@{/logout}" method="post">
	<input type="submit" value="注销">
</form>

这时候,当我们点击注销的时候,就自动退出了,security默认退出到/login资源,也就是退出到login页面,如果我们想退出之后回到首页该怎么做了?我们可以定制注销跳转资源

// 定制退出成功后,去到哪个地址
http.logout(cust -> {
	cust.logoutSuccessUrl("/");  // 退出成功,去到首页
});

2. security与thymeleaf整合

        我们可以利用thymeleaf的一些表达式和security整合的标签来控制权限资源的显示与隐藏

2.1 添加依赖

2.1.1 定义整合包版本

<properties>
	<java.version>1.8</java.version>
	<thymeleaf-extras-springsecurity.version>3.0.4.RELEASE</thymeleaf-extras-springsecurity.version>
</properties>

2.1.2 添加整合包

<!-- 引入 thymeleaf与security整合包-->
<dependency>
    <groupId>org.thymeleaf.extras</groupId>
    <artifactId>thymeleaf-extras-springsecurity5</artifactId>
    <version>${thymeleaf-extras-springsecurity.version}</version>
</dependency>

注意:这里有兼容性问题,在boot2.1之前用的是 thymeleaf-extras-springsecurity4,因为这里版本是2.3,所以需要使用thymeleaf-extras-springsecurity5

2.2 引入security整合名称空间

<html  xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">

注意:这里名称空间还是用thymeleaf-extras-springsecurity4即可 

2.3 重要属性

2.3.1 sec:authorize——认证

        该属性可以使用函数isAuthenticated()是否认证作为属性值,例如:

<div sec:authorize="!isAuthenticated()"> <!-- 如果没认证 -->
	<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/login}">请登录</a></h2>
</div>

也可以使用函数 hasRole()判断当前用户是否有某种权限,例如:

<div sec:authorize="hasRole('VIP1')">
	<h3 sec:authentication="">普通武功秘籍</h3>
	<ul>
		<li><a th:href="@{/level1/1}">罗汉拳</a></li>
		<li><a th:href="@{/level1/2}">武当长拳</a></li>
		<li><a th:href="@{/level1/3}">全真剑法</a></li>
	</ul>
</div>

2.3.2 sec:authentication——认证信息

        该属性可以获取一些认证信息,例如用户名,当前用户所拥有的角色等,例如:

<div sec:authorize="isAuthenticated()">   <!-- 如果认证了 -->
	<h2> <span sec:authentication="name"><!-- 当前登录用户 -->
		</span>,您好,您的角色有:<span sec:authentication="principal.authorities"></span><!-- 当前登录用户所属角色 -->
	</h2>
	<form th:action="@{/logout}" method="post">
		<input type="submit" value="注销">
	</form>
</div>

2.4 记住我功能

在配置类中开启记住我功能,下次登录可以免登录

http.rememberMe();

2.5 定制登录页

security默认给出的的登录页比较丑,我们可以定制我们自己的登录页

操作步骤:

1)准备自己的login.html

<div align="center">
	<form th:action="@{/userlogin}" method="post">
		用户名:<input name="user"/><br>
		密码:<input name="pwd"><br/>
		<input type="checkbox" name="rememberMe"/> 记住我<br/>
		<input type="submit" value="登陆">
	</form>
</div>

2)在配置类中配置定制的登录页

http.authorizeRequests(authorize -> authorize
				.antMatchers("/","/css/**", "/index").permitAll()  // 访问首页、静态资源所有用户可以访问
				.antMatchers("/level1/**").hasRole("VIP1") 		// 配置访问level1下的所有资源需要角色VIP1的用户
				.antMatchers("/level2/**").hasRole("VIP2")
				.antMatchers("/level3/**").hasRole("VIP3")
		)
		//.formLogin()   // 开启自动配置的登录功能  如果访问没有权限,就会跳转/login来到登录页面(security自带的)
       .formLogin()
		.usernameParameter("user")
		.passwordParameter("pwd")
		.loginPage("/userlogin");

注意:默认post形式的 /login代表处理登陆,一但定制loginPage;那么 loginPage的post请求就是登陆

3)配置记住我(可选配置)

http.rememberMe().rememberMeParameter("rememberMe");

注意:这里的rememberMeParameter的参数值与登录界面的保持一致。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值