没写完,推荐下面的博客
推荐博客<查看pom依赖、数据库sql、实体类、数据映射>:SpringSecurity框架
推荐博客<查看SpringSecurity整合JWT+Oauth2认证>:SpringSecurity整合JWT+Oauth2认证
一 创建项目
测试浏览器:建议使用谷歌的无痕模式,不然浏览器有缓存。
1. 创建项目
输入名称:springbootJwt
选择依赖->创建
项目路径<不需要的文件可以删掉>
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>
<!--父类2.7.4-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.4</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<!--项目说明-->
<groupId>com.xxx</groupId>
<artifactId>springbootJwt</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>springbootJwt</name>
<description>springbootJwt</description>
<!--版本配置1.8-->
<properties>
<java.version>1.8</java.version>
</properties>
<!--依赖-->
<dependencies>
<!--security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mybatis-plus-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.5.2</version>
</dependency>
<!-- 集成MySQL连接 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<!--devtools-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>-->
<!--processor-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>-->
<!--test-->
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>-->
<!--security-test-->
<!-- <dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>-->
<!--hutool-all-->
<!-- <dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.7.17</version>
</dependency>-->
<!--commons-io-->
<!-- <dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.11.0</version>
</dependency>-->
</dependencies>
</project>
2. 编写测试类
1. controller
package com.xxx.springbootjwt.controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class TestController {
@GetMapping("/slogan")
public String slogan() {
return "slogan ok !!!";
}
}
2. 访问
访问:http://127.0.0.1:8080/slogan
自动跳转 http://127.0.0.1:8080/login
security 自带的登录页面
用户名: user 密码:控制台打印生成的密码
输入用户名,密码 点击Sign in
自动跳转到 http://127.0.0.1:8080/slogan
3. 配置文件设置账号密码
路径:src/main/resources/application.yml
spring:
security:
user:
name: user
password: 123456
roles: manager
访问:http://127.0.0.1:8080/slogan
自动跳转 http://127.0.0.1:8080/login
输入用户名, 密码 点击sign in
自动跳转到 http://127.0.0.1:8080/slogan
4. UserDetailsService
1. 应用配置类
package com.xxx.springbootjwt.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* 应用配置类
*/
@Configuration
public class ApplicationConfig {
@Bean
public PasswordEncoder getPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
2. service 控制器
路径: src/main/java/com/xxx/springbootjwt/service/UserService.java
package com.xxx.springbootjwt.service;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
/**
*
*/
@Slf4j
@RequiredArgsConstructor //实现PasswordEncoder构造有参方法
@Service
public class UserService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("获取的账号 >>> {}", username);
// 1. 数据库判断账号啊是否存在,不存在抛出异常
if (!username.equals("user")) {
throw new UsernameNotFoundException("用户不存在");
}
// 2. 根据账号查询到的密码(注册时候已经加密过)进行解析,或者直接把账号密码放入到构造方法
String pwd = passwordEncoder.encode("123456");
/*该用户拥有多个角色,每个角色用都好隔开*/
List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal");
return new User(username, pwd, grantedAuthorities);
}
}
3. 重启->登录,查看运行
5. 数据库设计
1. 数据库表sql
表名:security
表和数据sql:
/*
Navicat Premium Data Transfer
Source Server : localhost
Source Server Type : MySQL
Source Server Version : 80012
Source Host : localhost:3306
Source Schema : security
Target Server Type : MySQL
Target Server Version : 80012
File Encoding : 65001
Date: 11/10/2022 16:16:19
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for role
-- ----------------------------
DROP TABLE IF EXISTS `role`;
CREATE TABLE `role` (
`rid` int(11) NOT NULL AUTO_INCREMENT,
`role_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '名称',
`role_name_zh` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '' COMMENT '中文名称',
PRIMARY KEY (`rid`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '权限表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of role
-- ----------------------------
INSERT INTO `role` VALUES (1, 'ROLE_dba', '数据库管理员');
INSERT INTO `role` VALUES (2, 'ROLE_admin', '系统管理员');
INSERT INTO `role` VALUES (3, 'ROLE_user', '用户');
-- ----------------------------
-- Table structure for sec_user
-- ----------------------------
DROP TABLE IF EXISTS `sec_user`;
CREATE TABLE `sec_user` (
`uid` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '',
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT '',
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户表' ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sec_user
-- ----------------------------
INSERT INTO `sec_user` VALUES (1, 'root', '123456');
INSERT INTO `sec_user` VALUES (2, 'admin', '123456');
INSERT INTO `sec_user` VALUES (3, 'fj', '123456');
-- ----------------------------
-- Table structure for user_role
-- ----------------------------
DROP TABLE IF EXISTS `user_role`;
CREATE TABLE `user_role` (
`urid` int(11) NOT NULL AUTO_INCREMENT,
`uid` int(11) NULL DEFAULT NULL,
`rid` int(11) NULL DEFAULT NULL,
PRIMARY KEY (`urid`) USING BTREE
) ENGINE = MyISAM AUTO_INCREMENT = 1 CHARACTER SET = utf8 COLLATE = utf8_general_ci COMMENT = '用户权限关联表' ROW_FORMAT = Fixed;
-- ----------------------------
-- Records of user_role
-- ----------------------------
INSERT INTO `user_role` VALUES (1, 1, 1);
INSERT INTO `user_role` VALUES (2, 1, 2);
INSERT INTO `user_role` VALUES (3, 1, 3);
INSERT INTO `user_role` VALUES (4, 2, 1);
SET FOREIGN_KEY_CHECKS = 1;
2. ide链接数据库,生成pojo
-
Database -> + -> Data Source -> mysql -> 输入数据库信息-> OK
-
选择 生成pojo
-
选择要存放的目录,点击ok
-
查看生成目录
3. 配置数据库链接
路径:src/main/resources/application.yml
spring:
security:
user:
name: user
password: 123456
roles: manager
datasource:
url: jdbc:mysql://localhost:3306/security?characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root
password: 123456
driver-class-name: com.mysql.cj.jdbc.Driver
# mybatis配置
mybatis-plus:
# xml文件路径
mapper-locations: classpath:mapper/*.xml
# 实体类路径
type-aliases-package: com.xxx.springbootjwt.pojo
configuration:
# 驼峰转换
map-underscore-to-camel-case: true
# 是否开启缓存
cache-enabled: false
# 打印sql
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
# 全局配置
global-config:
# 数据库字段驼峰下划线转换
db-column-underline: true
# id自增类型(数据库id自增)
id-type: 0
4. 修改实体类
- 修改sec_user
package com.xxx.springbootjwt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@TableName("sec_user")
public class SecUser extends Model<SecUser> {
private static final long serialVersionUID = -2109089699649055035L;
@TableId(value = "uid",type = IdType.AUTO)
private Long uid;
@TableField("username")
private String username;
@TableField("password")
private String password;
}
- 修改role
package com.xxx.springbootjwt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@TableName("role")
public class Role extends Model<Role> {
private static final long serialVersionUID = -2109089699649055035L;
@TableId(value = "rid", type = IdType.AUTO)
private Long rid;
@TableField("role_name")
private String roleName;
@TableField("role_name_zh")
private String roleNameZh;
}
- 修改user_role
package com.xxx.springbootjwt.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.extension.activerecord.Model;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@TableName("user_role")
public class UserRole extends Model<UserRole> {
private static final long serialVersionUID = -2109089699649055035L;
@TableId(value = "urid", type = IdType.AUTO)
private Long urid;
@TableField("uid")
private Long uid;
@TableField("rid")
private Long rid;
}
5. 添加mapper接口类
- SecUserMapper
package com.xxx.springbootjwt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.springbootjwt.pojo.SecUser;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface SecUserMapper extends BaseMapper<SecUser> {
/**
*用户id虎丘该用户的角色列表
*
*/
List<SecUser> selectSecUserByUid(@Param("uid") Long uid);
}
- RoleMapper
package com.xxx.springbootjwt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.springbootjwt.pojo.Role;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface RoleMapper extends BaseMapper<Role> {
/**
*用户id虎丘该用户的角色列表
*
*/
List<Role> selectRoleByUid(@Param("uid") Long uid);
}
- UserRoleMapper
package com.xxx.springbootjwt.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.xxx.springbootjwt.pojo.UserRole;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface UserRoleMapper extends BaseMapper<UserRole> {
/**
*用户id虎丘该用户的角色列表
*
*/
List<UserRole> selectUserRoleByUid(@Param("uid") Long uid);
}
6. 添加mapper.xml
- SecUserMapper.xml
路径:src/main/resources/mapper/SecUserMapper.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.xxx.springbootjwt.mapper.SecUserMapper">
<select id="selectSecUserByUid" resultType="com.xxx.springbootjwt.pojo.SecUser" parameterType="java.lang.Long">
select * from sec_user where uid =#{uid}
</select>
</mapper>
- RoleMapper.xml
路径:src/main/resources/mapper/RoleMapper.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.xxx.springbootjwt.mapper.RoleMapper">
<select id="selectRoleByUid" resultType="com.xxx.springbootjwt.pojo.Role" parameterType="java.lang.Long">
select r.* from role r inner join user_role ur where ur.uid =#{uid} and r.rid = ur.rid
</select>
</mapper>
- UserRoleMapper.xml
路径:src/main/resources/mapper/UserRoleMapper.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.xxx.springbootjwt.mapper.UserRoleMapper">
<select id="selectUserRoleByUid" resultType="com.xxx.springbootjwt.pojo.UserRole" parameterType="java.lang.Long">
select * from user_role where uid =#{uid}
</select>
</mapper>
7. 修改service控制器
路径: src/main/java/com/xxx/springbootjwt/service/UserService.java
package com.xxx.springbootjwt.service;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xxx.springbootjwt.mapper.RoleMapper;
import com.xxx.springbootjwt.mapper.SecUserMapper;
import com.xxx.springbootjwt.pojo.Role;
import com.xxx.springbootjwt.pojo.SecUser;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
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.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.stream.Collectors;
/**
* UserDetailsService实体类
*/
@Slf4j
@RequiredArgsConstructor //实现PasswordEncoder构造有参方法
@Service
public class UserService implements UserDetailsService {
private final PasswordEncoder passwordEncoder;
private final SecUserMapper secUserMapper;
private final RoleMapper roleMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("获取的账号 >>> {}", username);
// 1. 数据库判断账号啊是否存在,不存在抛出异常
/* if (!username.equals("user")) {
throw new UsernameNotFoundException("用户不存在");
}*/
// 2. 根据账号查询到的密码(注册时候已经加密过)进行解析,或者直接把账号密码放入到构造方法
QueryWrapper<SecUser> wrapper = new QueryWrapper<>();
wrapper.eq("username", username);
SecUser secUser = secUserMapper.selectOne(wrapper);
if (secUser == null) {
throw new UsernameNotFoundException("账号不存在");
}
String pwd = passwordEncoder.encode(secUser.getPassword());
//根据用户id获取该用户的角色列表
List<Role> roles = roleMapper.selectRoleByUid(secUser.getUid());
if (roles == null) {
//返回空的列表
return new User(username, pwd, AuthorityUtils.createAuthorityList());
}
/*该用户拥有多个角色,每个角色用都好隔开*/
//List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal");
//Collection<? extends GrantedAuthority> roleNames;
List<SimpleGrantedAuthority> collect = roles.stream().map(role -> new SimpleGrantedAuthority(role.getRoleName())).collect(Collectors.toList());
return new User(username, pwd, collect);
}
}
8. 测试
访问:http://127.0.0.1:8080/slogan
跳转登录
跳转成功
查看控制台