一.什么是SpringSecurity
百度百科:
Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
个人理解:在web开发中,安全是一个非常重要的问题,之前经常使用过滤器和拦截器实现一些安全和权限的问题,SpringSecurity就是一个能够解决安全问题和一些功能权限,访问权限,菜单权限等问题的框架.
二.SpringSecurity简单实践
开始之前要了解到的东西
- WebSecurityConfiguerAdapter:适配者模式,我们要继承这个类来自定义策略.
- AuthenticationManagerBuilder:建造者模式,
- @EnableWebSecurity:开启WebSecurity模式,EnableXXX开启XXX模式.
- Authentication:认证
- AuthoriZation:授权
准备工作:
创建一个Springboot项目,依赖如下:
<dependencies>
<--整合thymeleaf的依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<--web依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<--Security依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<---shymeleaf整合Security依赖->
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
写一个自动配置类继承WebSecurityConfigurerAdapter类,重写 configure(HttpSecurity http)进行授权,重新 configure(AuthenticationManagerBuilder auth) 方法进行认证.
package com.dlam.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;
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*
授权
authorizeRequests():认证请求
antMatchers():要认证哪些请求
permitAll():所有权限
hasRole:有什么权限的才能访问
链式编程,表达的是, authorizeRequests()来认证antMatchers("/")这个请求hasRole("vip1")需要vip1的权限.
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
//首页所有人可以访问,功能页有权限的用户才能访问
http.authorizeRequests()
.antMatchers("/").permitAll()
.antMatchers("/vip1/**").hasRole("vip1")
.antMatchers("/vip2/**").hasRole("vip2")
.antMatchers("/vip3/**").hasRole("vip3");
//关闭防止网站攻击.这个是注销的时候是get请求,所以要取消这个网址网站攻击
http.csrf().disable();
//没有权限会跳到登陆页面,需要开启登陆页面
http.formLogin().loginPage("/toLogin").loginProcessingUrl("/login");
http.rememberMe().rememberMeParameter("remember");
//开启注销功能 情况cookie 清空session 注销成功跳转到/
http.logout().logoutSuccessUrl("/index");
}
/*
认证
inMemoryAuthentication():从内存中取数据
jdbcAuthentication():从数据库中取数据
passwordEncoder(new BCryptPasswordEncoder()):对密码进行加密
withUser:用户名
password:密码
roles:权限
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder())
.withUser("dlam").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2")
.and()
.withUser("atm").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1")
.and()
.withUser("root").password(new BCryptPasswordEncoder().encode("123456")).roles("vip1","vip2","vip3");
}
}
controller控制视图跳转:
package com.dlam.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class RouterController {
@RequestMapping({"/","/index"})
public String index(){
return "index";
}
@RequestMapping("/toLogin")
public String toLogin(){
return "views/login";
}
@RequestMapping("/vip1/{id}")
public String vip1(@PathVariable("id") int id){
return "views/vip1/"+id;
}
@RequestMapping("/vip2/{id}")
public String vip2(@PathVariable("id") int id){
return "views/vip2/"+id;
}
@RequestMapping("/vip3/{id}")
public String vip3(@PathVariable("id") int id){
return "views/vip3/"+id;
}
}
主页:
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>主页</h1>
<div id="vip1" sec:authorize="hasRole('vip1')">
<a href="/vip1/1">vip1-1</a><br>
<a href="/vip1/2">vip1-2</a><br>
<a href="/vip1/3">vip1-3</a>
</div>
<h6>-------------------</h6>
<div id="vip2" sec:authorize="hasRole('vip2')">
<a href="/vip2/1">vip2-1</a><br>
<a href="/vip2/2">vip2-2</a><br>
<a href="/vip2/3">vip2-3</a>
</div>
<h6>-------------------</h6>
<div id="vip3" sec:authorize="hasRole('vip3')">
<a href="/vip3/1">vip3-1</a><br>
<a href="/vip3/2">vip3-2</a><br>
<a href="/vip3/3">vip3-3</a>
</div>
<!--用户是否登陆-->
<div sec:authorize="!isAuthenticated()">
<a href="/toLogin">登陆</a>
</div>
<div sec:authorize="isAuthenticated()">
<a href="/logout">注销</a>
<div>
用户名: <span sec:authentication="name"></span>
</div>
</div>
</body>
</html>
登陆页:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>登陆页面</h2>
<form action="/login" method="post">
用户名: <input type="text" name="username"><br>
密码: <input type="password" name="password"><br>
<input type="checkbox" name="remember"><span>记住我</span>
<input type="submit">
</form>
</body>
</html>
三.总结:
- 非常中要的一点,源码中的注解是精髓,链式编程,不会用的时候点进去源码就知道怎么用.
- csrf:是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法.spring是默认开启的.
- 前端可以通过thymeleaf整合Security实现根据权限判断是否展示.
sec:authorize=“hasRole(‘vip1’)”:如果有vip1权限则展示.
sec:authorize="!isAuthenticated()":如果没有登陆则展示.
sec:authentication=“name”:取出登陆用户名.
等等.