官网: Spring Security 中文文档 参考手册 中文版
1.SpringSecurity知识
Java 领域老牌的权限管理框架当属 Shiro 了。 Shiro 有着众多的优点,例如轻量、简单、易于集成等。当然 Shiro 也有不足,例如对 OAuth2 支持不够,在 Spring Boot 面前无法充分展示自己的优势等等,特别是随着现在 Spring Boot 和 Spring Cloud 的流行,Spring Security 正在走向舞台舞台中央
对于一个权限管理框架而言,无论是 Shiro 还是 Spring Security,最最核心的功能,无非就是两方面:认证和授权
通俗点说,认证就是我们常说的登录,授权就是权限鉴别,看看请求是否具备相应的权限。
Spring Security 支持基于 URL 的请求授权(例如微人事)、支持方法访问授权以及对象访问授权。
安全这一块从来都有说不完的话题,一个简单的注册登录很好做,但是你要是考虑到各种各样的攻击,XSS、CSRF 等等,一个简单的注册登录也能做的很复杂。
幸运的是,即使你对各种攻击不太熟悉,只要你用了 Spring Security,就能自动避免掉很多攻击了,因为 Spring Security 已经自动帮我们完成很多防护了。
2.Springboot+Security+Mysql
1.这是项目界面图
2.创建数据库
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80020
Source Host : localhost:3306
Source Schema : security
Target Server Type : MySQL
Target Server Version : 80020
File Encoding : 65001
Date: 18/01/2022 18:51:47
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`id` int NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'admin');
INSERT INTO `role` VALUES (2, 'user');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` int NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, 'admin', '$2a$10$BR05R/2KEZasiHovU.5Seuq0vllT5SCRCDn5xmXEe8hF/4BO9OyrO');
INSERT INTO `user` VALUES (2, 'zhangsan', '$2a$10$BR05R/2KEZasiHovU.5Seuq0vllT5SCRCDn5xmXEe8hF/4BO9OyrO');
INSERT INTO `user` VALUES (3, 'zhaosi', '$2a$10$f/FUkz92i6xpHS/9sB7ZmO1gmm/0E748FzBC6FEfDqOmmHTcapMD2');
-- ----------------------------
-- Table structure for userrole
-- ----------------------------
DROP TABLE IF EXISTS `userrole`;
CREATE TABLE `userrole` (
`id` int NOT NULL AUTO_INCREMENT,
`uid` int NULL DEFAULT NULL,
`rid` int NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = DYNAMIC;
-- ----------------------------
-- Records of userrole
-- ----------------------------
INSERT INTO `userrole` VALUES (1, 1, 1);
INSERT INTO `userrole` VALUES (2, 1, 2);
INSERT INTO `userrole` VALUES (3, 2, 2);
SET FOREIGN_KEY_CHECKS = 1;
3.创建springboot项目
3.1pom.xml依赖
<?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.6.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.xmx</groupId>
<artifactId>springsecurity_j9_demo1</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<name>springsecurity_j9_demo1</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity5</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
3.2 application.properties配置
#视图解析器
spring.mvc.view.prefix=/
spring.mvc.view.suffix=.html
#mysql
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/security?characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=root
#dao
#与文件目录一致
mybatis.type-aliases-package=com.xmx.springsecurity_j9_demo1.entity
mybatis.mapper-locations=classpath:mapping/*.xml
3.3.静态资源五个
5.1 index.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>教务管理系统</title>
</head>
<body>
<h2>欢迎光临教务管理系统</h2>
<div sec:authorize="isAuthenticated()">
欢迎您:<span sec:authentication="name"></span>
<form th:action="@{/logout}" method="post">
<input type="submit" value="安全退出">
</form>
</div>
<div sec:authorize="!isAuthenticated()">
请 <a th:href="@{/userlogin}">用户登录</a>
</div>
<p sec:authorize="hasRole('admin')">
<a href="/admin/list"> 管理员后台 </a>
</p>
<p sec:authorize="hasRole('user')">
<a href="/user/list"> 用户后台 </a>
</p>
</body>
</html>
5.2 login.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<h2>登录</h2>
<form th:action="@{/userlogin}" method="post">
<p>用户名:<input type="text" name="username"> </p>
<p>密 码:<input type="password" name="pwd"> </p>
<p> <input type="submit" value="登 录"> </p>
</form>
</body>
</html>
5.3 error.html
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity5">
<head>
<meta charset="UTF-8">
<title>登录</title>
</head>
<body>
<div sec:authorize="isAuthenticated()">
没有权限访问,请<a th:href="@{/userlogin}">登录</a>
</div>
<a href="/">返回</a>
</body>
</html>
5.4 adminIndex.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h2>这是管理员登录后的页面!!</h2>
<a href="/">返回</a>
</body>
</html>
5.5 userIndex.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户</title>
</head>
<body>
<h2>用户登录后的页面!!</h2>
<a href="/">返回</a>
</body>
</html>
3.4.mapping
RoleDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xmx.springsecurity_j9_demo1.dao.RoleDao">
<select id="getRoles" parameterType="int" resultType="Role">
select * from role where id in(
select rid from userrole where uid=#{uid}
)
</select>
</mapper>
UserDao.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xmx.springsecurity_j9_demo1.dao.UserDao">
<resultMap id="userMap" type="User">
<result column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<!-- 调用方法返回一个集合对象存入到role属性中 -->
<collection property="role" column="id"
select="com.xmx.springsecurity_j9_demo1.dao.RoleDao.getRoles"/>
</resultMap>
<select id="userLogin" parameterType="string" resultMap="userMap">
select * from user where username =#{name}
</select>
</mapper>
剩余配置代码截图
3.5.Config层
SecurityController
package com.xmx.springsecurity_j9_demo1.config;
import com.xmx.springsecurity_j9_demo1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//业务逻辑层的接口对象
@Autowired
UserService userService;
//重写里面的方法
/**
* 对授权的请求的处理策略。
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().accessDeniedPage("/error.html");
http.authorizeRequests()
.antMatchers("/","/userlogin")
.permitAll()
//为URL添加访问权限
.antMatchers("/admin/**").hasRole("admin")
.antMatchers("/user/**").hasRole("user")
//其它的都拦截
.anyRequest().authenticated()
.and()
//登入配置
.formLogin()
.usernameParameter("username")
.passwordParameter("pwd")
.loginPage("/userlogin")
.successForwardUrl("/index")
//退出
.and()
.logout().logoutSuccessUrl("/");
}
/**
* 配置系统中的用户,密码,及角色
* @param auth
* @throws Exception
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
System.out.println(passwordEncoder().encode("123"));
//从数据库取到用户信息,并加载他的角色
auth.userDetailsService(userService).passwordEncoder(passwordEncoder());
/*auth.inMemoryAuthentication()
.withUser("admin")
.password(new BCryptPasswordEncoder().encode("123"))
.roles("admin","user")
.and()
.withUser("zhangsan")
.password(new BCryptPasswordEncoder().encode("666"))
.roles("user");*/
}
//指定密码的加密方式
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
3.6.Controller层
AdminController
package com.xmx.springsecurity_j9_demo1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class AdminController {
@RequestMapping("admin/list")
public String list(){
return "admin/adminIndex";
}
}
UserController
package com.xmx.springsecurity_j9_demo1.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class UserController {
@RequestMapping("/userlogin")
public String login(){
System.out.println("-------login---------");
return "login";
}
@RequestMapping("/index")
public String index(){
System.out.println("-------index---------");
return "index";
}
@RequestMapping("/user/list")
public String list(){
return "user/userIndex";
}
}
RoleDao
package com.xmx.springsecurity_j9_demo1.dao;
import com.xmx.springsecurity_j9_demo1.entity.Role;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface RoleDao {
/**
* 根据用户Id查询所有角色对象
* @param uid
* @return
*/
public List<Role> getRoles(int uid);
}
3.7.Dao层
UserDao
package com.xmx.springsecurity_j9_demo1.dao;
import com.xmx.springsecurity_j9_demo1.entity.User;
import org.apache.ibatis.annotations.Mapper;
@Mapper
public interface UserDao {
public User userLogin(String name);
}
3.8.实体类层
Role
package com.xmx.springsecurity_j9_demo1.entity;
public class Role {
private int id;
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
User
package com.xmx.springsecurity_j9_demo1.entity;
import java.util.List;
public class User{
private int id;
private String username;
private String password;
//角色处理,一个用户对象中包含有多个角色对象
private List<Role> role;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public List<Role> getRole() {
return role;
}
public void setRole(List<Role> role) {
this.role = role;
}
}
3.9.业务层
UserServiceImpl
package com.xmx.springsecurity_j9_demo1.service.impl;
import com.xmx.springsecurity_j9_demo1.dao.UserDao;
import com.xmx.springsecurity_j9_demo1.entity.Role;
import com.xmx.springsecurity_j9_demo1.entity.User;
import com.xmx.springsecurity_j9_demo1.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.List;
@Service
public class UserServiceImpl implements UserService {
@Autowired
UserDao userDao;
@Override
public User userLogin(String name) {
return null;
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userDao.userLogin(username);
if(user == null){
throw new UsernameNotFoundException("用户名" + username + "不存在!");
}
//定义权限列表.
List<GrantedAuthority> list = new ArrayList<>();
// 用户可以访问的资源名称(或者说用户所拥有的权限) 注意:必须"ROLE_"开头
for(Role role : user.getRole()){
list.add(new SimpleGrantedAuthority("ROLE_"+role.getName()));
}
//创建一个让Security所认可的验证对象
org.springframework.security.core.userdetails.User userdetails = new
org.springframework.security.core.userdetails.User(username,user.getPassword(),list);
return userdetails;
}
}
UserService
package com.xmx.springsecurity_j9_demo1.service;
import com.xmx.springsecurity_j9_demo1.entity.User;
import org.springframework.security.core.userdetails.UserDetailsService;
public interface UserService extends UserDetailsService {
//用户登录
public User userLogin(String name);
}
4.运行结果:
4.1 管理员登录
点击登录,准备输入账号admin,密码123
admin登录运行结果:
点击管理员后台
点击返回,再点击用户后台
4.2用户登录
点击返回后,点击安全退出,准备输入账号zhangsan,密码123
只能看到普通用户后台,看不到管理员后台。这是因为权限控制了
点击用户后台
安全退出,输入错误账号密码后登录运行结果
4.3 没有登录,强行进入用户后台,
地址栏输入:http://localhost:8080/user/list。还是会跳登录界面
运行结果:
4.4 用户登录后,强行进入管理员后台,
地址栏输入:http://localhost:8080/admin/list
运行结果: