springboot+security
pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>springboot-05-security</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springboot-05-security</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--thymeleaf依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
<version>3.0.2.RELEASE</version>
</dependency>
<!--引入security依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-config</artifactId>
<version>5.7.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.启动类
package com.example.security;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* 1.引入springbootSecurity依赖
* 2.编写springSecurity的配置类
* 注解:@EnableWebSecurity extends WebSecurityConfigurerAdapter
* 3.控制请求的访问权限
*/
@SpringBootApplication
public class Springboot05SecurityApplication {
public static void main(String[] args) {
SpringApplication.run(Springboot05SecurityApplication.class, args);
}
}
3.MyPasswordEncoder
package com.example.security.config;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @PackageName: com.example.security.config
* @ClassName: MyPasswordEncoder
* @author: zhangpan
* @data: 2022/11/17 16:25
*/
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence charSequence) {
return charSequence.toString();
}
@Override
public boolean matches(CharSequence charSequence, String s) {
return s.equals(charSequence.toString());
}
}
4.MySecurityConfig
package com.example.security.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;
/**
* @PackageName: com.example.security.config
* @ClassName: MySecurityConfig
* @author: zhangpan
* @data: 2022/11/17 15:00
*/
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//定制请求的授权规则
http.authorizeRequests()
//主路径所有人都可以访问
.antMatchers("/").permitAll()
//其他请求都需要验证
.antMatchers("/level1/**").hasRole("VIP1")
.antMatchers("/level2/**").hasRole("VIP2")
.antMatchers("/level3/**").hasRole("VIP3");
//开启自动配置的登录功能 效果:如果没有登陆,没有权限就会来到登陆页面
http.formLogin().usernameParameter("user").passwordParameter("pwd").loginPage("/userlogin");
//1、 /login来到登陆页面
//2、 重定向到/login?error表示登陆失败
//3、 更多详细规则
//4、 默认post形式的/login代表处理登陆
//5、 一旦定制loginPage;那么loginPage的post请求就是登陆
//开启自动配置注销功能
http.logout().logoutSuccessUrl("/"); //注销成功后来到首页
// http.logout(); // 注销成功后返回userlogin?logout页面 http://localhost:8080/userlogin?logout
//1、访问 /logout 表示用户注销 并清空session
//2、注销成功会返回 /login?logout 页面
//防止跨站工具,get,post
http.csrf().disable(); //关闭csrf功能,注销失败可能的原因
//开启记住我功能
http.rememberMe().rememberMeParameter("remember");
//登录成功以后,将cookie发给浏览器保存。以后访问页面带上这个cookie,只要通过检查就可以免登录
//点击注销会删除cookie
}
/**
* 定义认证规则
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//账号密码这些数据正常情况下应该从数据库中读取
auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
.withUser("zhangsan").password("123456").roles("VIP1","VIP2")
.and()
.withUser("lisi").password("123456").roles("VIP2","VIP3")
.and()
.withUser("wangwu").password("123456").roles("VIP1","VIP3");
}
}
5.SercurityController
package com.example.security.controller;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @PackageName: com.example.security.controller
* @ClassName: SercurityController
* @author: zhangpan
* @data: 2022/11/16 16:45
*/
@Controller
public class SercurityController {
private final String PREFIX = "page/";
/**
* 欢迎页面
* @return
*/
@GetMapping("/")
public String index() {
return "welcome";
}
/**
* @PreAuthorize注解提供了基于表达式的访问控制,需要某个权限才可以,ROLE_前缀
* @return
*/
@PreAuthorize("hasAnyRole('VIP1')")
@RequestMapping("/role")
public String role() {
return "vip1,vip2";
}
/**
* 登录页面
* @return
*/
@GetMapping("/userlogin")
public String loginPage() {
return PREFIX + "login";
}
/**
* level1页面映射
* @param path
* @return
*/
@GetMapping("/level1/{path}")
public String level1(@PathVariable("path") String path) {
return PREFIX+"level1/"+ path;
// return "page/level1/"+ path;
}
/**
* level2页面映射
* @param path
* @return
*/
@GetMapping("/level2/{path}")
public String level2(@PathVariable("path") String path) {
return PREFIX+"level2/"+ path;
// return "page/level2/"+ path;
}
/**
* level3页面映射
* @param path
* @return
*/
@GetMapping("/level3/{path}")
public String level3(@PathVariable("path") String path) {
return PREFIX+"level3/"+ path;
// return "page/level3/"+ path;
}
}
6.页面结构如下图
7.welcome
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf.extras-springsecurity4">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>welcome</title>
</head>
<body>
<h1 align="center">欢迎光临武林秘籍管理系统</h1>
<!--如果没认证显示游客你好等...-->
<div sec:authorize="!isAuthenticated()">
<h2 align="center">游客你好,如果想查看武林秘籍 <a th:href="@{/userlogin}">请登录</a></h2>
</div>
<!--如果认证了,则显示账号名称和角色权限-->
<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>
<hr>
<!--当拥有vip1权限时可以访问普通秘籍-->
<div sec:authorize="hasRole(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>
<!--当拥有vip2权限时可以访问高级秘籍-->
<div sec:authorize="hasRole(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>
<!--当拥有vip3权限时可以访问绝世秘籍-->
<div sec:authorize="hasRole(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>
</body>
</html>
8.login
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<h1 align="center">欢迎登录武林秘籍管理系统</h1>
<hr>
<div align="center">
<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>
</div>
</body>
</html>
9.level1.1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>罗汉拳</title>
</head>
<body>
<a href="/">返回</a>
<h1>罗汉拳</h1>
<p>罗汉拳站中央,打起来不要慌。</p>
</body>
</html>
10.level1.2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>武当太极</h1>
<p>武当太极站中央,打起来不要慌。</p>
</body>
</html>
11.level1.3
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>全真剑法</h1>
<p>全真剑法站中央,打起来不要慌。</p>
</body>
</html>
12.level2.1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>八卦掌</h1>
<p>八卦掌站中央,打起来不要慌。</p>
</body>
</html>
13.level2.2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>七伤拳</h1>
<p>七伤拳站中央,打起来不要慌。</p>
</body>
</html>
14.level2.3
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>梯云纵</h1>
<p>梯云纵站中央,打起来不要慌。</p>
</body>
</html>
15.level3.1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>龟派气功</h1>
<p>龟派气功站中央,打起来不要慌。</p>
</body>
</html>
16.level3.2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>豆豆波</h1>
<p>豆豆波站中央,打起来不要慌。</p>
</body>
</html>
17.level3.3
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>魔灌光杀炮</h1>
<p>魔灌光杀炮站中央,打起来不要慌。</p>
</body>
</html>
f="/">返回</a>
<h1>龟派气功</h1>
<p>龟派气功站中央,打起来不要慌。</p>
</body>
</html>
16.level3.2
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>豆豆波</h1>
<p>豆豆波站中央,打起来不要慌。</p>
</body>
</html>
17.level3.3
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/">返回</a>
<h1>魔灌光杀炮</h1>
<p>魔灌光杀炮站中央,打起来不要慌。</p>
</body>
</html>