主要内容
1. 安全
2. Spring Security
1 概述
Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型。
他可以实现强大的web安全控制。对于安全控制,我们仅需引入spring-boot-starter-security模块,
进行少量的配置,即可实现强大的安全管理。
几个类:
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式
概念:
应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。
这两个主要区域是Spring Security 的两个目标。
“认证”(Authentication),是建立一个他声明的主体的过程(一个“主体”一般是指用户,
设备或一些可以在你的应用程序中执行动作的其他系统)。
登录验证。
“授权”(Authorization)指确定一个主体是否允许在你的应用程序执行一个动作的过程。
为了抵达需要授权的店,主体的身份已经有认证过程建立。
对某种资源是否能访问。
这个概念是通用的而不只在Spring Security中。
1. 先创建一个没有Security相关模块的工程

2 登录,认证,授权
注意: 编写代码:仿照QuickStart的案例写
/**
* @author Joe Grandja
*/
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// @formatter:off
@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")
);
}
// @formatter:on
@Bean
public UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("user")
.password("password")
.roles("USER")
.build();
return new InMemoryUserDetailsManager(userDetails);
}
}
1. 引入SpringSecurity
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
2. 编写SpringSecurity的配置类
`@EnableWebSecurity //这个注解带了个@Configuration 所以不用再为这个配置类加上该注解
public class MySecurityConfig extends WebSecurityConfigurerAdapter`
3. 定义授权规则:重写configure()
@EnableWebSecurity //这个注解带了个@Configuration 所以不用再为这个配置类加上该注解
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//自己定义授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
//super.configure(http);不用父类的规则,我们自己定义授权规则
http.authorizeRequests().antMatchers("/").permitAll()
.antMatchers("/level1/**").hasRole("VIP1")
.antMatchers("/level2/**").hasRole("VIP2")
.antMatchers("/level3/**").hasRole("VIP3");
//开启自动配置的登录功能:如果没有登录,没有权限就来到登录页面
http.formLogin();
//1. Login来到登录页
//2. 重定向到/Login?error表示登录失败
//3. 更多详细规则
}
}
4. 定义认证规则:重写userDetailsService()
@Bean
protected UserDetailsService userDetailsService() {
UserDetails userDetails = User.withDefaultPasswordEncoder()
.username("zhangsan").password("123456").roles("VIP1","VIP2").build();
UserDetails userDetails1 = User.withDefaultPasswordEncoder()
.username("lisi").password("123456").roles("VIP1", "VIP3").build();
UserDetails userDetails2 = User.withDefaultPasswordEncoder()
.username("wangwu").password("123456").roles("VIP1","VIP2", "VIP3").build();
//InMemoryUserDetailsManager() : 有一个构造可以传若干个UserDetails。
return new InMemoryUserDetailsManager(userDetails, userDetails1, userDetails2);
}
注意:怎么找到官方文档的QuickStart



5. 测试:其他资源代码,直接粘贴了老师的。
测试成功
3 注销功能
1. 开启自动配置的注销功能:写在我们自定义的SpringSecurity的配置类中

http.logout();
2. 在登录页面写一个 退出 表达
注意: 退出必须POST提交:security的规定
<!--退出必须POST提交:security的规定-->
<form th:action="@{/logout}" method="post">
<input type="submit" value="注销"/>
</form>
3. 测试一下:

注销成功并且来带http://localhost:8080/login?logout 页面
4. 定制注销成功后返回的页面:注销成功后,来到首页
http.logout().logoutSuccessUrl("/");
5. 测试一下
测试成功,但是在首页点注销,跳转到首页。
这样页面没有提示,不太好。

6. 改进:
根据角色权限显示菜单
登陆成功后:不显示 请登录
没有登录时:不显示注销
要先引入SpirngSecurity和Thymeleaf的整合模块,才能使用Thymeleaf对SpirngSecurity支持
1. 引入了SpirngSecurity和Thymeleaf的整合模块
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
2. 在页面:引入相关的名称空间。
注意我们当前项目导入的springsecurity版本是5
<html xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf/org/thymeleaf-extras-springsecurity5">
3. 编写index.html页面
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<!--没有认证时显示:-->
<div sec:authorize="!isAuthenticated()">
<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/login}">请登录</a></h2>
</div>
<!--认证了显示:-->
<div sec:authorize="isAuthenticated()">
<!--显示登陆名和权限-->
<h2><span sec:authentication="name"></span>,你好,你的角色是有:
<span sec:authentication="principal.authorities"></span>
</h2>
<!--退出必须POST提交:security的规定-->
<form th:action="@{/logout}" method="post">
<input type="submit" value="注销"/>
</form>
</div>
4. 测试

5. 根据权限显示不同菜单
<div sec:authorize="hashRole('VIP1')">
<h3>普通武功秘籍</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>
<div sec:authorize="hashRole('VIP2')">
<h3>高级武功秘籍</h3>
<ul>
<li><a th:href="@{/level2/1}">太极拳</a></li>
<li><a th:href="@{/level2/2}">七伤拳</a></li>
<li><a th:href="@{/level2/3}">梯云纵</a></li>
</ul>
</div>
<div sec:authorize="hashRole('VIP3')">
<h3>绝世武功秘籍</h3>
<ul>
<li><a th:href="@{/level3/1}">葵花宝典</a></li>
<li><a th:href="@{/level3/2}">龟派气功</a></li>
<li><a th:href="@{/level3/3}">独孤九剑</a></li>
</ul>
</div>
6. 测试:没有登录时

测试登录:Role:VIP1 VIP2

测试成功
5 记住我
服务开启时.
当浏览器关闭后,再打开页面就需要重新登录。
我们实现浏览器关闭后,再打开页面不需要登录。
在我们写的自定义SpringSecurity的配置类:开启
@EnableWebSecurity //这个注解带了个@Configuration 所以不用再为这个配置类加上该注解
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
//自己定义授权规则
@Override
protected void configure(HttpSecurity http) throws Exception {
...
//开启自动配置的记住我功能
http.rememberMe();
}

原理:
勾选了记住我后,在我们登陆成功后SpringSecurity会为浏览器发送一个cookies,cookies名为
rememeber-me。

它的过期时间是7-21号(现在是7/7)

所以这14天以内,只要我们再次访问该页面,就不需要在登录。
点击注销时,会将cookies删除。
6 定制登录页面
在自定义的SpringSecurity配置类中,用我们自己的login页面
配置http.formLogin();

//开启自动配置的登录功能:如果没有登录,没有权限就来到登录页面
http.formLogin().loginPage("/userlogin");
同时修改welcome.html页面中的请求路径:
<h2 align="center">游客您好,如果想查看武林秘籍 <a th:href="@{/userlogin}">请登录</a></h2>
通过/userlogin请求,会被controller中的方法处理,然后来到我们自定义的登录页面
/pages/login.html。
那么这个login.html肯定有一个提交表单的请求:怎么将这些数据给SpringSecurity让它来处理呢。
原来SpringSecurity:
默认如果有/login请求且是POST:那它就会去处理认证的。
我们把login.html的页面的提交请求设置为/login
但是现在 http.formLogin().loginPage("/userlogin");
一旦定制loginPage,那么loginPage中指定的/userlogin POST请求就被当做了登陆验。
我们可以将login.html的页面的提交请求设置为/userlogin,
同时在指定一下用户名和密码等参数传给springsecurity
1. login.html
<!--默认POST形式的/login代表处理登陆:SpringSecurity回去处理-->
<form th:action="@{/userlogin}" method="post">
用户名:<input name="user"/><br>
密码:<input name="pwd"><br/>
<input type="submit" value="登陆">
</form>
2. 配置类
http.formLogin().usernameParameter("user").passwordParameter("pwd")
.loginPage("/userlogin")
再给登录页面加一个记住我复选框
//参数:remember传给登陆页面
http.rememberMe().rememberMeParameter("remember");
<form th:action="@{/userlogin}" method="post">
用户名:<input name="user"/><br>
密码:<input name="pwd"><br/>
<input type="checkbox" name="remember">记住我<br/>
<input type="submit" value="登陆">
</form>
测试成功。