概要:
Spring Security是一个功能强大且高度可定制的身份验证和访问控制框架。它是用于保护基于Spring的应用程序的实际标准。
Spring Security是一个框架,致力于为Java应用程序提供身份验证和授权。与所有Spring项目一样,Spring Security的真正强大之处在于可以轻松扩展以满足自定义要求
Spring Security 与 Shiro 很像,除了类不一样,名字不一样;都是做认证、授权操作。
Spring Security(安全)
在web开发中安全第一位,过滤器、拦截器、黑白名单等
安全不是功能性需求,没有考虑到安全,网站也能实现与运行;但存在用户隐私泄露,与漏洞的风险。
开发网站时:安全应该在何时考虑?设计之初就应考虑。
web系统的权限主要分为:功能权限,查看权限,菜单权限,通常实现这些权限控制一般用拦截器、过滤器操作,但是需要耗费大量资源写代码。从 mvc --> spring --> spring boot 一路在简化,所以繁琐的认证是不希望看到的,Spring Security由此诞生。
AOP:横切--配置类...
认识SpringSecurity:
Spring Security 是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型,他可以实现强大的Web安全控制,对于安全控制,我们仅需要引入 spring-boot-starter-security 模块,进行少量的配置,即可实现强大的安全管理!
记住几个类:
WebSecurityConfigurerAdapter:自定义Security策略
AuthenticationManagerBuilder:自定义认证策略
@EnableWebSecurity:开启WebSecurity模式 @Enable**** 注解开启某个功能
Spring Security的两个主要目标是 “认证” 和 “授权”(访问控制)。
“认证”(Authentication)
身份验证是关于验证您的凭据,如用户名/用户ID和密码,以验证您的身份。
身份验证通常通过用户名和密码完成,有时与身份验证因素结合使用。
“授权” (Authorization)
授权发生在系统成功验证您的身份后,最终会授予您访问资源(如信息,文件,数据库,资金,位置,几乎任何内容)的完全权限。
这个概念是通用的,而不是只在Spring Security 中存在。
参考官网:Spring Security
查看我们自己项目中的版本,找到对应的帮助文档: #servlet-applications 8.16.4
使用Spring Boot + Spring Security + Thymeleaf
举例操作步骤(其他成熟的例子):Spring Boot + Spring Security + Thymeleaf 举例_ThinkingInGIS的博客-CSDN博客
(1).pom.xml文件中导入如下依赖
值得注意:spring boot的版本最好在 2.0.0以上 2.0.9以下,一般用2.0.7
<!-- spring security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--thymeleaf模板页面种使用spring security的整合包,可以去掉版本号使用-->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
(2).yml文件种关闭 thymeleaf的缓存,使我们可以随时调试页面不用重启
spring:
thymeleaf:
cache: false #关闭thymeleaf模板引擎的缓存,方便开发时随时调试
(3).java文件中新建一个config目录,创建spring security 配置类:SpringSecurityConfig
package com.hp.boot.config;
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.crypto.bcrypt.BCryptPasswordEncoder;
/**
* AOP 横切 :拦截器!
* 不用改变代码就可以执行类似拦截器的操作,比拦截器好玩多了,拦截器要大量代码功能也没这么多
* @EnableWebSecurity 注解:打开WebSecurity
*/
@EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
/**
* 链式编程方法
* 授权:configure(HttpSecurity http)[设置http安全策略]
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//自定义,首页所有人可以访问,功能页只有对应有权限的人才可以访问
//authorizeRequests认证请求,
http.authorizeRequests()
//antMatchers设置某一个路径,permitAll所有人可以访问
.antMatchers("/", "/index", "/login").permitAll()
//antMatchers设置某一个路径,hasRole某个角色的人才可以访问
//.antMatchers("/level/**").hasRole("admin")
.antMatchers("/level1/**").hasRole("vip1")
.antMatchers("/level2/**").hasRole("vip2");
//没有访问权限的,设置默认开启跳转到登陆页 http://localhost:8081/项目名/login
//.loginPage()可以自定义formLogin登陆页面地址
//.loginProcessingUrl()自定义登录认证请求
//.usernameParameter()自定义登录表单提交的用户名name,.passwordParameter()自定义登录表单提交的密码name (般配合.loginProcessingUrl()一起使用)
//使用loginPage()自定义登录页面后,登录页面的表单请求要改成.loginPage("/toLogin")中一样的路径才可以登录成功
//使用loginProcessingUrl()自定义认证请求后,登录页面的表单请求就可以使用loginProcessingUrl()中自定义的认证请求
//但是使用自定义认证请求后,登录提交的"用户名","密码" 的name默认名称是 "username","password";
//如果是其他名字,则还需要使用.usernameParameter("*").passwordParameter("*") 自定义"用户名","密码"的name
http.formLogin().loginPage("/toLogin").usernameParameter("user").passwordParameter("pwd").loginProcessingUrl("/login");
//防止网站攻击:get 不安全(明文传输),post可以
//csrf(跨站请求伪造,通过一些get方式让网站收到攻击,springboot 默认开启,需要关闭) disable()关闭
http.csrf().disable();
//设置开启注销,正常注销后跳转首页或登录页:使用logoutSuccessUrl方法
//.deleteCookies("remove").invalidateHttpSession(true);删除cookie清空session
//.logoutSuccessUrl("/**");注销成功的页面;logoutUrl("/**");注销页面
http.logout().logoutSuccessUrl("/");
//.rememberMe()开启登录页的记住我功能,本身是个cookie 默认保存两周
//.rememberMeParameter()自定义登陆页表单提交时 记住我 勾选框的name名称
//(勾选登录后用户被保存进cookie 叉掉浏览器再访问,用户还在可以直接访问;浏览器可以手动清理就失效了)
//如果登录页是自定义的,那么提交登录时记住我这个功能的 勾选框和表单的name
//也是需要根据需求自定义的,就需要使用.rememberMeParameter()进行自定义
http.rememberMe().rememberMeParameter("remember");
}
/**
* 认证:configure(AuthenticationManagerBuilder auth)
* 密码编码:PasswordEncoder
* 在Spring Security 5.0+中新增了很多加密方法
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//auth.inMemoryAuthentication()从内存中获取认证[从内存读取用户进行认证是一个特点]
//auth.jdbcAuthentication()从数据库中获取认证[正常情况认证数据都是从数据库读取]
//.withUser("用户名").password("密码").roles("角色1","角色2")
//passwordEncoder(new BCryptPasswordEncoder())获取认证时进行密码编码选择加密,可以new很多种编码格式的加密
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
//withUser需要认证的用户,password认证用户的密码[new BCryptPasswordEncoder()与上面的方法同步使用进行明文密码编码转换],roles用户的角色可以是多个
.withUser("admin").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
//多个用户时,使用and()方法可以无限拼接多个用户
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1");
}
}
(4).controller层的页面路由设计:
package com.hp.boot.controller;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class PageController {
/**
* 测试Spring security 路径
* @return
*/
@RequestMapping({"/","index"})
public String home(){
return "index";
}
@RequestMapping("level1/{id}")
public String level1(@PathVariable("id") int id){
System.out.println(id);
return "view/level1/"+id;
}
@RequestMapping("level2/{id}")
public String level2(@PathVariable("id") int id){
return "view/level2/"+id;
}
}
(5).html模板页面按照controller中路由返回的目录结构创建,如下图:
(6).上图中的index.html中,在页面使用 Security 控制菜单权限等...
<!DOCTYPE>
<!--sec = url = http://www.thymeleaf.org+"/"+"pom.xml导入的thymeleaf和springsecurity整合包的名称" -->
<html
xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>Hello Thymeleaf resources</title>
</head>
<body>
<div>
<h1>Spring Sucurity : index.html</h1>
<!-- 登陆显示登出按钮 isAuthenticated() 判断登录-->
<div sec:authorize="isAuthenticated()">
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>
<a th:href="@{/logout}">登出</a>
</div>
<!-- 未登陆显示登录按钮 !isAuthenticated() 判断未登录-->
<div sec:authorize="isAuthenticated()">
用户名:<span sec:authentication="name"></span>
角色:<span sec:authentication="principal.authorities"></span>
<a th:href="@{/login}">登入</a>
</div>
<!--菜单权限:根据用户角色控制 -->
<ul>
<li>首页</li>
<li>用户</li>
<li sec:authorize="hasRole('vip1')"><a th:href="@{/level1/1}">区域</a></li>
<li sec:authorize="hasRole('vip2')"><a th:href="@{/level2/2}">功能</a></li>
</ul>
</div>
</body>
</html>