1、基础技术框架
技术名称 | 版本 |
SpringBoot | 2.1.9.RELEASE |
MyBatis-plus | 3.3.1 |
MySQL | 8.0.11 |
SpringSecurity | 5.1.6.RELEASE |
jjwt | 0.9.0 |
lombok | 1.18.10 |
guava | 30.1.1-jre |
hutool-all | 5.5.2 |
druid | 1.2.3 |
swagger3 | 3.0 |
aop | 1.9.4 |
fastjson | 1.2.47 |
2、完整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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.zzg</groupId>
<artifactId>Meta</artifactId>
<version>0.0.1-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.9.RELEASE</version>
<relativePath /> <!-- lookup parent from repository -->
</parent>
<properties>
<java.version>1.8</java.version>
<maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- 集成Mybatis-plus -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.3.1</version>
</dependency>
<!-- 集成MySQL 驱动包 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.11</version>
</dependency>
<!-- 集成SpringSecurity 安全框架 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!-- 集成JWT-->
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
<!--集成lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- 集成guava 工具包 -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>30.1.1-jre</version>
</dependency>
<!-- 集成hutool-all 工具包 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.5.2</version>
</dependency>
<!--druid 数据库连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.3</version>
</dependency>
<!-- swagger3 接口文档生成器 -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
<exclusions>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-core</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.plugin</groupId>
<artifactId>spring-plugin-metadata</artifactId>
<version>2.0.0.RELEASE</version>
</dependency>
<!-- 集成SpringAop -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<!-- 集成Alibaba fastjson -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>
3、初始化脚本
/*
Navicat MySQL Data Transfer
Source Server : 192.168.1.73
Source Server Type : MySQL
Source Server Version : 80015
Source Host : 192.168.1.73:3306
Source Schema : banan_test
Target Server Type : MySQL
Target Server Version : 80015
File Encoding : 65001
Date: 05/11/2021 19:14:17
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for t_sys_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_auth`;
CREATE TABLE `t_sys_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`auth_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '权限名称',
`permission` varchar(200) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '权限标识',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 7 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统权限' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_auth
-- ----------------------------
INSERT INTO `t_sys_auth` VALUES (1, '系统用户编辑权限', 'sys:user:edit');
INSERT INTO `t_sys_auth` VALUES (2, '系统用户查询权限', 'sys:user:view');
INSERT INTO `t_sys_auth` VALUES (3, '系统角色编辑权限', 'sys:role:edit');
INSERT INTO `t_sys_auth` VALUES (4, '系统角色查询权限', 'sys:role:view');
INSERT INTO `t_sys_auth` VALUES (5, '系统权限编辑权限', 'sys:auth:edit');
INSERT INTO `t_sys_auth` VALUES (6, '系统权限查询权限', 'sys:auth:view');
INSERT INTO `t_sys_auth` VALUES (7, '系统日志编辑权限', 'sys:log:edit');
INSERT INTO `t_sys_auth` VALUES (8, '系统日志查询权限', 'sys:log:view');
-- ----------------------------
-- Table structure for t_sys_log
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_log`;
CREATE TABLE `t_sys_log` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`method` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求方法',
`uri` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求地址',
`params` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '请求参数',
`time` bigint(10) NULL DEFAULT NULL COMMENT '请求时间',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_log
-- ----------------------------
INSERT INTO `t_sys_log` VALUES (2, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (3, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (4, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (5, 'GET', '/log/listData', 'page=1&limit=10&id=2', 0);
INSERT INTO `t_sys_log` VALUES (6, 'GET', '/log/listData', 'page=1&limit=10&id=', -1);
INSERT INTO `t_sys_log` VALUES (7, 'POST', '/log/delete', '[{\"id\":1}]', 0);
INSERT INTO `t_sys_log` VALUES (8, 'GET', '/log/listData', 'page=1&limit=10&id=', 0);
INSERT INTO `t_sys_log` VALUES (9, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (10, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (11, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (12, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (13, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (14, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (15, 'GET', '/log/listData', 'page=2&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (16, 'GET', '/auth/list', '', 0);
INSERT INTO `t_sys_log` VALUES (17, 'GET', '/auth/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (18, 'GET', '/auth/bind', 'id=1', 0);
INSERT INTO `t_sys_log` VALUES (19, 'GET', '/auth/roleListData', 'authId=1&page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (20, 'GET', '/auth/list', '', 0);
INSERT INTO `t_sys_log` VALUES (21, 'GET', '/auth/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (22, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (23, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (24, 'GET', '/log/listData', 'page=3&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (25, 'GET', '/log/listData', 'page=2&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (26, 'GET', '/auth/list', '', 0);
INSERT INTO `t_sys_log` VALUES (27, 'GET', '/auth/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (28, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (29, 'GET', '/log/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (30, 'GET', '/auth/list', '', -1);
INSERT INTO `t_sys_log` VALUES (31, 'GET', '/auth/listData', 'page=1&limit=10', 0);
INSERT INTO `t_sys_log` VALUES (32, 'GET', '/log/list', '', 0);
INSERT INTO `t_sys_log` VALUES (33, 'GET', '/log/listData', 'page=1&limit=10', 0);
-- ----------------------------
-- Table structure for t_sys_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role`;
CREATE TABLE `t_sys_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_name` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '角色名称',
`role_code` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '角色编码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统角色' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_role
-- ----------------------------
INSERT INTO `t_sys_role` VALUES (1, '普通员工', 'USER');
INSERT INTO `t_sys_role` VALUES (2, '项目经理', 'PM');
-- ----------------------------
-- Table structure for t_sys_role_auth
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_role_auth`;
CREATE TABLE `t_sys_role_auth` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
`auth_id` bigint(20) NULL DEFAULT NULL COMMENT '权限ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 11 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '角色权限关系' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_role_auth
-- ----------------------------
INSERT INTO `t_sys_role_auth` VALUES (1, 2, 1);
INSERT INTO `t_sys_role_auth` VALUES (2, 1, 2);
INSERT INTO `t_sys_role_auth` VALUES (3, 2, 2);
INSERT INTO `t_sys_role_auth` VALUES (4, 2, 3);
INSERT INTO `t_sys_role_auth` VALUES (5, 1, 4);
INSERT INTO `t_sys_role_auth` VALUES (6, 2, 4);
INSERT INTO `t_sys_role_auth` VALUES (7, 2, 5);
INSERT INTO `t_sys_role_auth` VALUES (8, 1, 6);
INSERT INTO `t_sys_role_auth` VALUES (9, 2, 6);
INSERT INTO `t_sys_role_auth` VALUES (10, 2, 7);
INSERT INTO `t_sys_role_auth` VALUES (11, 2, 8);
-- ----------------------------
-- Table structure for t_sys_user
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user`;
CREATE TABLE `t_sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户名称',
`nickname` varchar(100) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户昵称',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '用户密码',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '系统用户' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_user
-- ----------------------------
INSERT INTO `t_sys_user` VALUES (1, 'user', 'C3Stones', '$2a$10$RFjGxPxq8EZokh89z.DcIeSpBJHfeRozfXUZSHnfN14bb94JKVRia');
INSERT INTO `t_sys_user` VALUES (2, 'system', '管理员', '$2a$10$RFjGxPxq8EZokh89z.DcIeSpBJHfeRozfXUZSHnfN14bb94JKVRia');
-- ----------------------------
-- Table structure for t_sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `t_sys_user_role`;
CREATE TABLE `t_sys_user_role` (
`id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'ID',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户ID',
`role_id` bigint(20) NULL DEFAULT NULL COMMENT '角色ID',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 3 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_0900_ai_ci COMMENT = '用户角色关系' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of t_sys_user_role
-- ----------------------------
INSERT INTO `t_sys_user_role` VALUES (1, 1, 1);
INSERT INTO `t_sys_user_role` VALUES (2, 2, 2);
SET FOREIGN_KEY_CHECKS = 1;
4、项目结构截图:
5、springsecurity handler 定义
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.zzg.common.vo.Response;
import cn.hutool.http.HttpStatus;
/**
* 无权限处理类
*
* @author zzg
*
*/
@Component
public class UserAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response,
AccessDeniedException accessDeniedException) throws IOException {
Response<String> responseBody = Response.error(HttpStatus.HTTP_UNAUTHORIZED, "Unauthorized", "用户未认证");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.zzg.common.vo.Response;
import cn.hutool.http.HttpStatus;
/**
* 登录失败处理类
*
* @author zzg
*
*/
@Component
public class UserLoginFailureHandler implements AuthenticationFailureHandler {
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException {
Response<String> responseBody = Response.error(HttpStatus.HTTP_BAD_REQUEST, "Bad Request", "请求失败");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.zzg.common.vo.Response;
import com.zzg.security.entity.UserDetails;
import com.zzg.security.jwt.JwtTokenUtil;
import cn.hutool.http.HttpStatus;
/**
* 登录成功处理类
*
* @author zzg
*
*/
@Component
public class UserLoginSuccessHandler implements AuthenticationSuccessHandler {
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throws IOException {
UserDetails userDetails = (UserDetails) authentication.getPrincipal();
Map<String, Object> paramter = new HashMap<String, Object>();
paramter.put("username", userDetails.getUsername());
String jwtToken = JwtTokenUtil.createToken(paramter);
Response<String> responseBody = Response.error(HttpStatus.HTTP_OK, "Login Success", jwtToken);
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.zzg.common.vo.Response;
import cn.hutool.http.HttpStatus;
/**
* 登出成功处理类
*
* @author zzg
*
*/
@Component
public class UserLogoutSuccessHandler implements LogoutSuccessHandler {
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
throws IOException {
Response<String> responseBody = Response.error(HttpStatus.HTTP_OK, "Logout Success", "用户退出成功");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
package com.zzg.security.handler;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import com.alibaba.fastjson.JSON;
import com.zzg.common.vo.Response;
import cn.hutool.http.HttpStatus;
/**
* 未登录处理类
*
* @author zzg
*
*/
@Component
public class UserNotLoginHandler implements AuthenticationEntryPoint {
@Override
public void commence(HttpServletRequest request, HttpServletResponse response,
AuthenticationException authException) throws IOException {
Response<String> responseBody = Response.error(HttpStatus.HTTP_UNAUTHORIZED, "Unauthorized", "用户未认证");
response.getWriter().write(JSON.toJSONString(responseBody));
}
}
6、springsecurity UserDetails 定义
package com.zzg.security.entity;
import java.io.Serializable;
import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import com.zzg.sys.entity.User;
import lombok.Data;
import lombok.EqualsAndHashCode;
/**
* 系统用户详情
*
* @author zzg
*
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class UserDetails extends User
implements org.springframework.security.core.userdetails.UserDetails, Serializable {
private static final long serialVersionUID = 1L;
/**
* 用户角色
*/
private Collection<GrantedAuthority> authorities;
/**
* 账号是否过期
*/
private boolean isAccountNonExpired = false;
/**
* 账号是否锁定
*/
private boolean isAccountNonLocked = false;
/**
* 证书是否过期
*/
private boolean isCredentialsNonExpired = false;
/**
* 账号是否有效
*/
private boolean isEnabled = true;
/**
* 获得用户权限
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return authorities;
}
/**
* 判断账号是否过期
*/
@Override
public boolean isAccountNonExpired() {
return isAccountNonExpired;
}
/**
* 判断账号是否锁定
*/
@Override
public boolean isAccountNonLocked() {
return isAccountNonLocked;
}
/**
* 判断证书是否过期
*/
@Override
public boolean isCredentialsNonExpired() {
return isCredentialsNonExpired;
}
/**
* 判断账号是否有效
*/
@Override
public boolean isEnabled() {
return isEnabled;
}
}
7、springsecurity UserDetailsService定义
package com.zzg.security.service;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.springframework.beans.BeanUtils;
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.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.zzg.security.entity.UserDetails;
import com.zzg.sys.entity.Role;
import com.zzg.sys.entity.User;
import com.zzg.sys.service.RoleService;
import com.zzg.sys.service.UserService;
/**
* 用户登录Service
*
* @author zzg
*
*/
@Service
public class UserDetailsService implements org.springframework.security.core.userdetails.UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private RoleService roleService;
/**
* 根据用户名查用户信息
*
* @param username 用户名称
* @return 用户详细信息
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
QueryWrapper<User> queryWrapper = new QueryWrapper<>();
queryWrapper.eq("username", username);
User user = userService.getOne(queryWrapper);
if (user != null) {
UserDetails userDetails = new UserDetails();
BeanUtils.copyProperties(user, userDetails);
// 用户角色
Set<GrantedAuthority> authorities = new HashSet<>();
// 查询用户角色
List<Role> roleList = roleService.findByUserId(userDetails.getId());
roleList.forEach(role -> {
authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));
});
userDetails.setAuthorities(authorities);
return userDetails;
}
return null;
}
}
8、springsecurity AuthenticationProvider定义
package com.zzg.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component;
import com.zzg.security.entity.UserDetails;
import com.zzg.security.service.UserDetailsService;
import cn.hutool.core.util.StrUtil;
/**
* 用户登录验证处理类
*
* @author zzg
*
*/
@Component
public class UserAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
/**
* 身份验证
*/
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
// 获取用户名
String username = (String) authentication.getPrincipal();
// 获取密码
String password = (String) authentication.getCredentials();
UserDetails userDetails = (UserDetails) userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new UsernameNotFoundException("用户名不存在");
}
if (!StrUtil.equals(username, userDetails.getUsername())
|| !new BCryptPasswordEncoder().matches(password, userDetails.getPassword())) {
throw new BadCredentialsException("用户名或密码错误");
}
return new UsernamePasswordAuthenticationToken(userDetails, password, userDetails.getAuthorities());
}
/**
* 支持指定的身份验证
*/
@Override
public boolean supports(Class<?> authentication) {
return true;
}
}
9. jwt 工具类定义
package com.zzg.security.jwt;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
public class JwtTokenUtil {
/** 密钥secret */
private static String secret = "meta";
/** 过期时间,单位为秒 */
private static long expire = 7 * 24 * 60 * 60;
/**
* 解析token
*
* @param jsonWebToken
* @return
*/
public static Claims parseToken(String token) {
Claims claims = null;
try {
claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
} catch (Exception e) {
return claims;
}
return claims;
}
/**
* 新建token
*
* @param audience
* @param issuer
*
* @return
*/
public static String createToken(Map<String, Object> paramter) {
if (Objects.isNull(paramter)) {
paramter = new HashMap<>();
}
// 过期时间
Date expireDate = new Date(System.currentTimeMillis() + expire * 1000);
return Jwts.builder().setHeaderParam("typ", "JWT") // 设置头部信息
.setClaims(paramter) // 装入自定义的用户信息
.setExpiration(expireDate) // token过期时间
.signWith(SignatureAlgorithm.HS512, secret) // 密钥
.compact();
}
/**
* 刷新token
*
* @param audience
* @param issuer
*
* @return
*/
public static String referToken(Map<String, Object> paramter) {
if (Objects.isNull(paramter)) {
paramter = new HashMap<>();
}
// 过期时间
Date expireDate = new Date(System.currentTimeMillis() + expire * 1000);
return Jwts.builder().setHeaderParam("typ", "JWT") // 设置头部信息
.setClaims(paramter) // 装入自定义的用户信息
.setExpiration(expireDate) // token过期时间
.signWith(SignatureAlgorithm.HS512, secret) // 密钥
.compact();
}
}
10.jwt 凭证验证拦截器
package com.zzg.security.filter;
import java.io.IOException;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;
import com.zzg.security.entity.UserDetails;
import com.zzg.security.jwt.JwtTokenUtil;
import com.zzg.security.service.UserDetailsService;
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Autowired
UserDetailsService userDetailsService;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
String authHeader = request.getHeader("Authorization");
if (authHeader != null && authHeader.startsWith("Bearer")) {
final String authToken = authHeader.substring("Bearer".length());
String username = (String) JwtTokenUtil.parseToken(authToken).get("username");
if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails != null) {
UsernamePasswordAuthenticationToken authentication =
new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
SecurityContextHolder.getContext().setAuthentication(authentication);
}
}
}
chain.doFilter(request, response);
}
}
11、springsecurity 配置对象
package com.zzg.security.conf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.method.configuration.EnableGlobalMethodSecurity;
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.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.zzg.security.UserAuthenticationProvider;
import com.zzg.security.filter.JwtAuthenticationTokenFilter;
import com.zzg.security.handler.UserAccessDeniedHandler;
import com.zzg.security.handler.UserLoginFailureHandler;
import com.zzg.security.handler.UserLoginSuccessHandler;
import com.zzg.security.handler.UserLogoutSuccessHandler;
import com.zzg.security.handler.UserNotLoginHandler;
/**
* 系统安全核心配置
*
* @author zzg
*
*/
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
public static final Logger logger = LoggerFactory.getLogger(WebSecurityConfig.class);
/**
* 无权限处理类
*/
@Autowired
private UserAccessDeniedHandler userAccessDeniedHandler;
/**
* 用户未登录处理类
*/
@Autowired
private UserNotLoginHandler userNotLoginHandler;
/**
* 用户登录成功处理类
*/
@Autowired
private UserLoginSuccessHandler userLoginSuccessHandler;
/**
* 用户登录失败处理类
*/
@Autowired
private UserLoginFailureHandler userLoginFailureHandler;
/**
* 用户登出成功处理类
*/
@Autowired
private UserLogoutSuccessHandler userLogoutSuccessHandler;
/**
* 用户登录验证
*/
@Autowired
private UserAuthenticationProvider userAuthenticationProvider;
/**
* jwt 拦截器
*/
@Autowired
JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
/**
* 加密方式
*
* @return
*/
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
/**
* 用户登录验证
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) {
auth.authenticationProvider(userAuthenticationProvider);
}
/**
* 安全权限配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 去掉 CSRF
http.csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 使用 JWT,关闭token
.and()
.httpBasic().authenticationEntryPoint(userNotLoginHandler)
.and()
.authorizeRequests()
// .anyRequest()
// .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证
.and()
.formLogin() //开启登录
.successHandler(userLoginSuccessHandler) // 登录成功
.failureHandler(userLoginFailureHandler) // 登录失败
.permitAll()
.and()
.logout()
.logoutSuccessHandler(userLogoutSuccessHandler)
.permitAll();
http.exceptionHandling().accessDeniedHandler(userAccessDeniedHandler); // 无权访问 JSON 格式的数据
http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); // JWT Filter
}
}
12、PostMan模拟前后端分离效果截图