编写:Horin
Spring 安全性是提供认证、授权和防范常见攻击的框架。由于对imperative和reactive应用程序的安全都提供了第一类支持,因此它是保护基于 Spring 的应用程序的事实上的标准。
有关功能的完整列表,请参见引用的Features部分。
Spring安全 中文文档
提示:以下是本篇文章正文内容,下面案例可供参考
1、添加依赖:pom.xml
<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.0modelVersion>
<parent>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-parentartifactId>
<version>2.6.7version>
<relativePath/>
parent>
<groupId>com.examplegroupId>
<artifactId>TheTokenartifactId>
<version>0.0.1-SNAPSHOTversion>
<name>TheTokenname>
<description>TheTokendescription>
<properties>
<java.version>1.8java.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-webartifactId>
dependency>
<dependency>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
<optional>trueoptional>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-devtoolsartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-testartifactId>
<scope>testscope>
dependency>
<dependency>
<groupId>org.mybatis.spring.bootgroupId>
<artifactId>mybatis-spring-boot-starterartifactId>
<version>2.2.0version>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-jdbcartifactId>
dependency>
<dependency>
<groupId>mysqlgroupId>
<artifactId>mysql-connector-javaartifactId>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-thymeleafartifactId>
dependency>
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
<dependency>
<groupId>org.thymeleaf.extrasgroupId>
<artifactId>thymeleaf-extras-springsecurity5artifactId>
dependency>
dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-maven-pluginartifactId>
<version>2.6.7version>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombokgroupId>
<artifactId>lombokartifactId>
exclude>
excludes>
configuration>
plugin>
plugins>
build>
project>
配置类:SecurityConfig.java
package com.example.thetoken.config;
import com.example.thetoken.service.serviceImpl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
@EnableWebSecurity // 开启MVC security安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
/**
* userDetailsService身份验证
*/
@Autowired
private UserDetailsServiceImpl userDetailsService;
/**
* 用户授权管理自定义配置
* @param http
* @throws Exception
*/
/**
* 用户身份认证自定义配置
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 明文加密
*/
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
/**
* 1、内存认证
*/
// auth.inMemoryAuthentication().passwordEncoder(encoder)
// .withUser("jsor").password(encoder.encode("12312333")).roles("common")
// .and()
// .withUser("wanglaoji").password(encoder.encode("123456")).roles("admin");
/**
* 2、UserDetailsService认证
*/
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
}
}
实现类:UserDetailsServiceImpl.java
package com.example.thetoken.service.serviceImpl;
import com.example.thetoken.domain.User;
import com.example.thetoken.domain.Authority;
import com.example.thetoken.mapper.UserMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* @Classname UserDetailsServiceImpl
* @Description 自定义一个UserDetailsService接口实现类进行用户认证信息封装
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
/**
* 查询用户信息
* selectUser():通过用户名查询用户密码
* selectAuths():查询该用户权限
*/
User user = userMapper.selectUser(s);
List<Authority> authorities = userMapper.selectAuths(s);
/**
* 封装用户权限
*/
List<SimpleGrantedAuthority> list = authorities.stream().map(
authority -> new SimpleGrantedAuthority(authority.getAuthority())).collect(Collectors.toList());
/**
* 将对应值传入security的User对象
*/
if(user!=null){
System.out.println(user.getUserName()+" "+user.getUserAccount()+" "+user.getUserPassword());
String userA = user.getUserAccount();
String pasA = user.getUserPassword();
System.out.println(list);
//数据库为明文密码,所以使用对象来转换为需要的加密格式
BCryptPasswordEncoder bCryptPasswordEncoder=new BCryptPasswordEncoder();
UserDetails userDetails=
new org.springframework.security.core.userdetails.User(userA, bCryptPasswordEncoder.encode(pasA), list);
System.out.println(userDetails);
return userDetails;
} else {
/**
* 不存在用户抛出为空
*/
return null;
}
}
}
实现类:UserMapper.java
package com.example.thetoken.mapper;
import com.example.thetoken.domain.Authority;
import com.example.thetoken.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;
import java.util.List;
@Mapper
public interface UserMapper {
//验证用户账号是否匹配
User selectUser(String userAccount);
//获取该用户名的权限
List<Authority> selectAuths(String userAccount);
}
SQL导出文件:springbootf.sql
/*
Navicat MySQL Data Transfer
Source Server : 127.0.0.1
Source Server Type : MySQL
Source Server Version : 50723
Source Host : localhost:3306
Source Schema : springbootf
Target Server Type : MySQL
Target Server Version : 50723
File Encoding : 65001
Date: 01/06/2022 19:19:38
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for authority
-- ----------------------------
DROP TABLE IF EXISTS `authority`;
CREATE TABLE `authority` (
`id` int(50) NOT NULL,
`authority` varchar(20) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of authority
-- ----------------------------
INSERT INTO `authority` VALUES (1, 'ROLE_admin');
INSERT INTO `authority` VALUES (2, 'ROLE_common');
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`user_id` int(5) NOT NULL AUTO_INCREMENT,
`user_name` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_account` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`user_password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL,
`sex` int(1) NOT NULL COMMENT '0-女,1-男',
PRIMARY KEY (`user_id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES (1, '江治雨', '8823', 'j12312333', 1);
INSERT INTO `user` VALUES (2, '周杰伦', '123', '123', 1);
INSERT INTO `user` VALUES (4, '邓丽君', 'dengli312884', '987654321', 0);
INSERT INTO `user` VALUES (6, '张国荣', '401', 'zgr', 1);
INSERT INTO `user` VALUES (7, 's', 's', '', 1);
-- ----------------------------
-- Table structure for user_authority
-- ----------------------------
DROP TABLE IF EXISTS `user_authority`;
CREATE TABLE `user_authority` (
`id` int(20) NOT NULL,
`user_id` int(50) NOT NULL,
`authority_id` int(50) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user_authority
-- ----------------------------
INSERT INTO `user_authority` VALUES (1, 1, 1);
INSERT INTO `user_authority` VALUES (2, 2, 2);
SET FOREIGN_KEY_CHECKS = 1;
映射文件:UserMapper.xml
DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.thetoken.mapper.UserMapper">
<resultMap id="BaseResultMap" type="com.example.thetoken.domain.User">
<id property="userId" column="user_id"/>
<result property="userName" column="user_name"/>
<result property="userAccount" column="user_account"/>
<result property="userPassword" column="user_password"/>
<result property="sex" column="sex"/>
resultMap>
<select id="selectUser" parameterType="string" resultMap="BaseResultMap">
select * from user where user_account = #{userAccount}
select>
<select id="selectAuths" parameterType="string" resultType="Authority">
select a.* from user c, authority a, user_authority ca
where
ca.user_id=c.user_id and ca.authority_id=a.id and c.user_account =#{userAccount}
select>
mapper>
省略:User实体类、Authority实体类
配置类:SecurityConfig.java
package com.example.thetoken.config;
import com.example.thetoken.service.serviceImpl.UserDetailsServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.access.AccessDeniedException;
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.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;
import java.io.IOException;
@EnableWebSecurity // 开启MVC security安全支持
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
/**
* 第三种身份验证
*/
@Autowired
private UserDetailsServiceImpl userDetailsService;
/**
* 用户授权管理自定义配置
* @param http
* @throws Exception
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);
/**
* 自定义授权
*/
http.authorizeRequests()
// 静态资源、登录、注册页面放行
.antMatchers("/login/**","/moban/**","/toLogin","/toZhuce").permitAll()
// .antMatchers("/templates/**").hasRole("common")
//管理员可以访问用户列表(接口list)
.antMatchers("/list").hasRole("admin")
.anyRequest().authenticated();
/**
* 自定义登录
*/
http.formLogin()
//跳转登陆页面接口
.loginPage("/toLogin")
//以下Controller接口无需编写
.loginProcessingUrl("/loginss")
//主页面接口
.defaultSuccessUrl("/");
/**
* 记住我
*/
http.rememberMe()
.rememberMeParameter("rememberme")
.tokenValiditySeconds(2000);
// 对cookie信息进行持久化管理
// .tokenRepository(tokenRepository());
/**
* 自定义无权限跳转页面
*/
http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {
@Override
public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException, ServletException {
// 如果是权限访问异常,则进行拦截到指定错误页面
RequestDispatcher dispatcher = httpServletRequest.getRequestDispatcher("/err");
dispatcher.forward(httpServletRequest, httpServletResponse);
}
});
}
/**
* 持久化Token存储
* @return
*/
@Bean
public JdbcTokenRepositoryImpl tokenRepository(){
JdbcTokenRepositoryImpl jr=new JdbcTokenRepositoryImpl();
jr.setDataSource(dataSource);
jr.setCreateTableOnStartup(false);
return jr;
}
/**
* 用户身份认证自定义配置
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
/**
* 明文加密
*/
BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
/**
* 1、内存认证
*/
// auth.inMemoryAuthentication().passwordEncoder(encoder)
// .withUser("jsor").password(encoder.encode("12312333")).roles("common")
// .and()
// .withUser("wanglaoji").password(encoder.encode("123456")).roles("admin");
/**
* 2、UserDetailsService认证
*/
auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
}
}
登录页面:index.html
注意事项:仅供参考结构,未上传css样式文件。
重点一,input的name属性必须固定,账号为username,密码为password。
重点二,form标签的action与配置类中的登录接口一样,spring会自动创建。
DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>欢迎登录title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link th:href="@{/login/css/style.css}" rel="stylesheet">
<link th:href="@{https://fonts.googleapis.com/css2?family=Noto+Sans+JP:wght@400;500;700&display=swap}" rel="stylesheet">
<script th:src="@{/login/js/jquery-3.1.1.min.js}">script>
<script th:src="@{/login/js/jquery.min.js}">script>
head>
<body>
<script th:if="${userList!=null}"> alert("账号或者密码输入错误!");script>
<div class="main">
<div class="logo text-center">
<h1> <a href="index.html">叭叭贰叁™ 进销系统a>h1>
div>
<div class="content-w3ls text-center" >
<form th:action="@{/loginss}" th:method="post">
<div class="wthree-field">
<input name="username" type="text" placeholder="用户名" />
div>
<div class="wthree-field">
<input name="password" type="password" placeholder="密码" />
div>
<div class="wthree-field">
<button class="btn" type="submit" >登录button>
div>
<div class="login-bottom">
<a th:href="@{/toZhuce}" class="">没有账户?创建一个。a>
div>
form>
div>
<div class="copyright">
<p>© 2021 Universe Signin Form. Made with music | Designed by <a
href="" target="_blank">Horina>p>
div>
div>
body>
html>
其中HTML页面、Controller跳转补充完成,就可以正常运行了。