基于SpringSecurity+JWT+Redis进行用户的认证和权限管理(一)

第一步

我们需要建立一个springboot工程,然后进行依赖的添加 我这里的springboot工程的版本是2.7.14 引入下方的依赖时,没有引发依赖冲突

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

        <!--引入web依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
        </dependency>

        <!--引入springsecurity依赖 作用: 安全框架,进行用户的认证和权限的管理-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

        <!-- 引入Mysql依赖 我这里使用的是Mysql8.0的依赖 -->
        <dependency>
            <groupId>com.mysql</groupId>
            <artifactId>mysql-connector-j</artifactId>
            <version>8.0.33</version>
        </dependency>

        <!-- 引入Mybatis 作用: 和数据库进行交互 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.2.2</version>
        </dependency>

        <!-- 引入lombok 作用: 减少代码量通过注解生成类的有参无参以及日志-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
        </dependency>

        <!-- 引入JWT 作用: 进行用户信息的加密-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>4.2.1</version>
        </dependency>

        <!-- 引入redis依赖 作用: 为了后面进行token验证 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <version>2.7.14</version>
        </dependency>

第二步

进行application.yml 配置文件的编写

# mysql注册  
# com.mysql.cj.jdbc.Driver       表示数据库的驱动 mysql8.0 驱动
# com.mysql.jdbc.Driver          这个是mysql5.xx 本版的驱动
# jdbc:mysql://127.0.0.1:3306    表示数据库的地址和端口号 我这里是本地连接。
# security_study                 表示的是数据库的名称
# useUnicode=true&characterEncoding=UTF-8&  设置字符编码集使用的是Unicode编码,字符集是UTF-8
#serverTimezone=Asia/Shanghai     设置时区   数据库8.0以上的版本需要设置时区,不设置时区会报错

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: 123456
    url: jdbc:mysql://127.0.0.1:3306/security_study?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai

# 配置Mybatis
mybatis:
  # 配置映射文件
  mapper-locations: classpath:mapper/*.xml
  # 配置实体映射包 作用: 在配置xml文件映射时我们可以不用写包名,直接写表名即可 下方的包表示的是项目    
  #中的实体类的包
  type-aliases-package: com.hxtz.springsecurity13demo.entity
  configuration:
    # 开启将下划线转成驼峰命名。 数据库中的表的字段一般以下划线命名,而java中的属性一般是以驼峰命名。这里将其进行了转换。
    map-underscore-to-camel-case: true
    # 开启控制台打印日志
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

# 配置签名密钥 这个密钥用于的是jwt签名密钥 内容是字符串可以自己随便写 我这里是MrCui 是我的署名
my:
  secretKey: "MrCui"

第三步 进行核心代码的编写。

  (1) 编写实体类要和数据库中的字段对应起来

这里用到了4个注解

@Data 帮我们生成了这个类的set() get() ,toString() 等方法

@NoArgsConstructor   生成类的无参构造
@AllArgsConstructor   生成类的有参构造
@Builder   将类改为建造者模式。

package com.hxtz.springsecurity13demo.entity;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @Author: cyb
 * @Date: 2023/8/3 10:35
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
@Builder
public class SysUser implements Serializable {
    private Integer userId;
    private String username;
    private String password;
    private String sex;
    private String address;
    private Integer enabled;
    private Integer accountNoExpired;
    private Integer credentialsNoExpired;
    private Integer accountNoLocked;
}
# 用户表
CREATE TABLE `sys_user` (
  `user_id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `username` varchar(255) DEFAULT NULL COMMENT '登陆名',
  `password` varchar(255) DEFAULT NULL COMMENT '密码',
  `sex` varchar(255) DEFAULT NULL COMMENT '性别',
  `address` varchar(255) DEFAULT NULL COMMENT '地址',
  `enabled` int(11) DEFAULT '1' COMMENT '是否启动账户0禁用 1启用',
  `account_no_expired` int(11) DEFAULT '1' COMMENT '账户是否没有过期0已过期 1 正常',
  `credentials_no_expired` int(11) DEFAULT '1' COMMENT '密码是否没有过期0已过期 1 正常',
  `account_no_locked` int(11) DEFAULT '1' COMMENT '账户是否没有锁定0已锁定 1 正常',
  PRIMARY KEY (`user_id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
# 用户角色表
CREATE TABLE `sys_role_user` (
  `uid` int(11) NOT NULL COMMENT '用户编号',
  `rid` int(11) NOT NULL COMMENT '角色编号',
  PRIMARY KEY (`uid`,`rid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
# 角色菜单表
CREATE TABLE `sys_role_menu` (
  `rid` int(11) NOT NULL COMMENT '角色表的编号',
  `mid` int(11) NOT NULL COMMENT '菜单表的编号',
  PRIMARY KEY (`mid`,`rid`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
# 角色表
CREATE TABLE `sys_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色ID',
  `rolename` varchar(255) DEFAULT NULL COMMENT '角色名称,英文名称',
  `remark` varchar(255) DEFAULT NULL COMMENT '备注',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;
# 菜单表
CREATE TABLE `sys_menu` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '编号',
  `pid` int(11) DEFAULT NULL COMMENT '父级编号',
  `name` varchar(255) DEFAULT NULL COMMENT '名称',
  `code` varchar(255) DEFAULT NULL COMMENT '权限编码',
  `type` int(11) DEFAULT NULL COMMENT '0代表菜单1权限2 url',
  `delete_flag` tinyint(4) DEFAULT '0' COMMENT '0代表未删除,1 代表已删除',
  PRIMARY KEY (`id`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC;

(2)编写mapper层 查询用户信息用来进行用户的认证。

java文件中的 @Param("userName")  要和 #{userName} 对应

/**
 * @Author: cyb
 * @Date: 2023/8/4 16:29
 * 获取用户信息
 */
@Mapper
public interface SysUserMapper {
    /**
     *  查询用户信息
     * @param userName  这里的userName要和mapper文件对应起来。
     * @return
     */
    SysUser queryUserByUserName(@Param("userName") String userName);
}
<?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.hxtz.springsecurity13demo.mapper.SysUserMapper">
    <select id="queryUserByUserName" resultType="sysUser">
        select user_id,username,`password`,sex,address,enabled,account_no_expired,credentials_no_expired,account_no_locked FROM
            sys_user
        WHERE username = #{userName};
    </select>
</mapper>

(3)编写Service层代码

/**
 * @Author: cyb
 * @Date: 2023/8/4 16:42
 */
public interface SysUserService {
    SysUser queryUserByUserName(String userName);
}
/**
 * @Author: cyb
 * @Date: 2023/8/4 16:43
 */
@Service
public class SysUserServiceImpl implements SysUserService {
    @Resource
    private SysUserMapper sysUserMapper;
    @Override
    public SysUser queryUserByUserName(String userName) {
        SysUser sysUser = sysUserMapper.queryUserByUserName(userName);
        return sysUser;
    }
}

(4)  实现 UserDetails接口   该接口是提供用户信息的核心接口。该接口实现仅仅存储用户的信息。

为什么要实现这个接口?参考这篇文章  一起搞清楚 Spring Security 中的 UserDetails

package com.hxtz.springsecurity13demo.component;

import com.hxtz.springsecurity13demo.entity.SysUser;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;

import java.util.Collection;
import java.util.List;

/**
 * @Author: cyb
 * @Date: 2023/8/4 16:52
 */
@Service
public class MyUserDetails implements UserDetails {
    private SysUser sysUser;
    private List<SimpleGrantedAuthority> authorityList;
    public MyUserDetails() {
    }
    public MyUserDetails(SysUser sysUser) {
        this.sysUser = sysUser;
    }

    /**
     *  获取权限信息
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {

        return authorityList;
    }

    /**
     *  获取密码
     * @return
     */

    @Override
    public String getPassword() {
        String password = this.sysUser.getPassword();
        this.sysUser.setPassword(null);
        return password;
    }

    /**
     *  获取用户名
     * @return
     */

    @Override
    public String getUsername() {

        return this.sysUser.getUsername();
    }

    /**
     *  判断账户是否过期
     * @return
     */

    @Override
    public boolean isAccountNonExpired() {
        return this.sysUser.getAccountNoExpired().equals(1);
    }

    /**
     *  判单账户是否加锁
     * @return
     */

    @Override
    public boolean isAccountNonLocked() {
        return this.sysUser.getAccountNoLocked().equals(1);
    }

    /**
     *  判断账户凭证是否过期
     * @return
     */

    @Override
    public boolean isCredentialsNonExpired() {
        return this.sysUser.getCredentialsNoExpired().equals(1);
    }

    /**
     * 判断账户是否启用
     * @return
     */

    @Override
    public boolean isEnabled() {
        return this.sysUser.getEnabled().equals(1);
    }

    public void setAuthorityList(List<SimpleGrantedAuthority> authorityList) {
        this.authorityList = authorityList;
    }
    public SysUser getSysUser(){
        return sysUser;
    }
}

(5) 注册Bean到Spring容器中 主要做用是为了配置springSecurity

这里面注册了3个Bean

首先注册  UserDeatisService 这个类主要是用来返回用户的信息

其次注册了 PasswordEncoder 这个类主要是用来进行密码的加密解密的在新版本的springsecurity框架中规定必须要注册密码编译器

最后注册了 SecurityFilterChain 安全适配器 这个类主要是用来拦截请求的。 查看用户是否有访问这个的权限

SecurityFilterChain是security新版的做法,以前是我们通过匿名内部类来进行 WebSecurityConfigurerAdapter 这个类的编写。

package com.hxtz.springsecurity13demo.config;

import com.hxtz.springsecurity13demo.JwtCheckFilter;
import com.hxtz.springsecurity13demo.component.MyAuthenticationSuccessHandler;
import com.hxtz.springsecurity13demo.component.MyLogoutSuccessHandler;
import com.hxtz.springsecurity13demo.component.MyUserDetails;
import com.hxtz.springsecurity13demo.entity.SysUser;
import com.hxtz.springsecurity13demo.service.impl.SysMenuServiceImpl;
import com.hxtz.springsecurity13demo.service.impl.SysUserServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
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.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

import javax.annotation.Resource;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: cyb
 * @Date: 2023/8/4 16:22
 * security配置类
 */
@EnableGlobalMethodSecurity(prePostEnabled = true) // 启用全局方法权限处理
@Slf4j
public class MySecurityConfig {
    @Resource
    private SysUserServiceImpl userService;

    // @Resource 
    // private SysMenuServiceImpl sysMenuService;  // 目前还没有用到后续会用到 这个service主要用来查看用户的权限信息的。
    @Resource
    private MyAuthenticationSuccessHandler successHandler;
    @Resource
    private MyLogoutSuccessHandler logoutHandler;
    @Resource
    private JwtCheckFilter jwtCheckFilter;

    /**
     *  注册UserDetailsService
     * @return
     */
    @Bean
    public UserDetailsService userDetailsService(){
        return username -> {
            // 在这里怎么处理username?
            SysUser sysUser = userService.queryUserByUserName(username);
            if (null==sysUser){
                throw new UsernameNotFoundException("用户不存在");
            }
/*  权限信息这里先不用管。目前我们只关注认证就可以了 后续会将这里进行修改。
            // 获取用户权限信息
            List<String> authList = sysMenuService.getUserMenuByUserId(sysUser.getUserId());
            List<SimpleGrantedAuthority> collect = authList.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
           
            myUserDetails.setAuthorityList(collect); // 将用户的权限信息放入到用户详细信息中
*/
            //  这里是用户的信息
            MyUserDetails myUserDetails = new MyUserDetails(sysUser);
            
            return myUserDetails;
        };

    }

    /**
     *  注册密码编译器
     * @return
     */
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**
     *  安全适配器
     * @param http
     * @return
     * @throws Exception
     */
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.csrf().disable(); //  先关闭跨域请求。
        http.formLogin().successHandler(successHandler).permitAll(); // 请求登录接口放行。
        http.logout().logoutSuccessHandler(logoutHandler);
        http.authorizeRequests().anyRequest().authenticated(); // 任何的请求都需要认证。
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS); // 禁用session域
        http.addFilterBefore(jwtCheckFilter, UsernamePasswordAuthenticationFilter.class); // 将自定义过滤器放在 过滤器之前
        return http.build();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
基于SpringBoot2、MyBatisPlus、Spring Security5.7、JWTRedis的开发框架可以提供以下功能和优势: 1. Spring Boot2是一个轻量级的Java开发框架,能够快速构建Web应用程序和微服务。它提供了自动配置和约定大于配置的设计理念,减少了开发的复杂性。 2. MyBatisPlus是一个在MyBatis基础上进行扩展的ORM框架,提供了更简洁、更便捷的数据库访问方式。它支持代码生成、自动SQL映射、分页查询等功能,能够进一步提高开发效率。 3. Spring Security5.7是一个基于Spring的身份认证和授权框架,可以进行用户认证、角色授权、API权限控制等。它提供了一套完整的解决方案,保护应用程序免受各种安全威胁。 4. JWT(Json Web Token)是一种用于跨网络进行身份验证的开放标准。它使用JSON对象作为令牌,可以在客户端和服务器之间传递信息。JWT具有无状态、可扩展、跨平台等特点,适用于分布式系统和移动应用程序。 5. Redis是一种高性能的键值存储系统,它支持数据持久化、集群模式、发布订阅等功能。在开发过程中,可以使用Redis存储JWT令牌、缓存数据等,提高系统的性能和可扩展性。 综上所述,基于SpringBoot2、MyBatisPlus、Spring Security5.7、JWTRedis的开发框架具有快速开发、高效数据库访问、可靠的安全保护和可扩展的分布式支持等优势。它可以帮助开发者快速构建稳定、安全、高性能的Web应用程序和微服务。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值