后台基础权限框架搭建实现[木字楠博客]

news2024/11/24 20:34:14

文章目录

    • 1、项目整合SpringSecurity
      • 1.1、引入SpringSecurity依赖
      • 1.2、启动测试
      • 1.3、自定义实体类继承UserDetails
      • 1.4、自定义配制文件
      • 1.5、重写loadUserByUsername方法
      • 1.6、自定义匿名访问注解
      • 1.8、编写SpringSecurity配制类

后台权限框架搭建:本项目权限主要依赖SpringSecurity实现,主要涉及的表有角色表菜单表以及角色菜单关联表等数据库表。权限部分功能的实现需要使用到自定义配制文件、自定义注解、自定义服务类等等…

1、项目整合SpringSecurity

1.1、引入SpringSecurity依赖

        <!--===================== SpringBoot相关依赖版本  =========================-->
        <springboot.version>2.5.5</springboot.version>
            <!-- security -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
                <version>${springboot.version}</version>
            </dependency>

1.2、启动测试

启动项目之后访问接口发现已经被SpringSecurity拦截,出现如下界面说明SpringSecurity已经成功引入

在这里插入图片描述

1.3、自定义实体类继承UserDetails

由于SpringSecurity默认提供的登陆接口会执行loadUserByUsername()方法,此方法的返回值为UserDetails,而SpringSecurity会根据返回值中的加密密码进行密码校验,所以我们需要自定义一个实体类来继承UserDetails

/**
 * @author 木字楠
 * @version 1.0
 * @description 用户信息
 * @date 2022/8/12
 */
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class User implements UserDetails {

    /**
     * 用户主键
     */
    private String id;

    /**
     * 用户名/OpenId
     */
    private String username;

    /**
     * 用户密码
     */
    private String password;

    /**
     * 用户登录方式(1 用户名  2 邮箱  3 QQ  4 微信)
     */
    private Integer loginType;

    /**
     * 是否开启邮箱登录(0 否  1是)
     */
    private Boolean emailLogin;

    /**
     * 是否禁用(0 正常  1禁用)
     */
    private Boolean disabled;

    /**
     * 用户名
     */
    private String nickname;

    /**
     * 用户头像
     */
    private String avatar;

    /**
     * 用户性别(-1 未知  0 仙女  1帅哥)
     */
    private String gender;

    /**
     * 用户邮箱
     */
    private String email;

    /**
     * 用户个人简介
     */
    private String personIntro;

    /**
     * ip地址
     */
    private String ipAddress;

    /**
     * ip来源
     */
    private String ipSource;

    /**
     * 用户创建时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime gmtCreate;

    /**
     * 用户信息更新时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime gmtUpdate;

    /**
     * 用户最近一次登录时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime lastLoginTime;

    /**
     * 浏览器
     */
    private String brower;

    /**
     * 操作系统
     */
    private String os;

    /**
     * 角色
     */
    private String role;

    /**
     * 权限列表
     */
    private Set<String> permissionList;

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        SimpleGrantedAuthority list = new SimpleGrantedAuthority(role);
        return Collections.singleton(list);
    }

    @Override
    public String getPassword() {
        return this.password;
    }

    @Override
    public String getUsername() {
        return this.username;
    }

    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    @Override
    public boolean isAccountNonLocked() {
        return true;
    }

    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    @Override
    public boolean isEnabled() {
        return true;
    }
}

1.4、自定义配制文件

引入依赖

        <!-- 自定义配置 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
        </dependency>

自定义配制信息

# custom Configuration
application:
  #Swagger Configuration
  swagger:
    isEnable: true
  #Super_admin Configuration
  highest-authority:
    highest-role-label: super_admin
    highest-role-secret: MuZiNan#$%^&*
    highest-permission: <*><*><*>

我们可以使用@Value的注解进行自定义配制信息的提取,但是那样做法太Low,而且不方便。这里我们采用更加优雅的方式来提起自定义注解信息!使用Properties配制文件来提取自定义配制信息!

/**
 * @author 木字楠
 * @version 1.0
 * @description 最高权限配制文件
 * @date 2022/8/12
 */
@Data
@ConfigurationProperties(HIGHEST_AUTHORITY)
public class HigestAuthorityProperties {

    /**
     * 最高权限角色标识
     */
    private String highestRoleLabel;

    /**
     * 最高权限角色秘钥
     */
    private String highestRoleSecret;

    /**
     * 最高权限标识
     */
    private String highestPermission;
}

我们是用常量的形式来简化字符串的拼接

# ConfigPropertiesConstant

/**
 * @author: 木字楠
 * @date: 2022/8/12
 * @version: 1.0
 */
public class ConfigPropertiesConstant {

    /**
     * 应用相关前缀,位于“Application”配置中
     */
    public static class Application {

        /**
         * 默认前缀
         */
        private static final String DEFAULT_PREFIX = "application";

        /**
         * JWT相关配置信息
         */
        public static final String JWT = DEFAULT_PREFIX + ".jwt";

        /**
         * 最高权限配制信息
         */
        public static final String HIGHEST_AUTHORITY = DEFAULT_PREFIX + ".highest-authority";

        /**
         * 阿里云Oss对象存储
         */
        public static final String ALIYUN_OSS = DEFAULT_PREFIX + ".aliyun.oss";

        /**
         * 七牛云Kodo对象存储
         */
        public static final String QINIU_KODO = DEFAULT_PREFIX + ".qiniu.kodo";

        /**
         * 服务器Ftp上传
         */
        public static final String ECS_FTP = DEFAULT_PREFIX + ".ecs.ftp";

    }

}

开启配制文件的使用

/**
 * @author 木字楠
 * @version 1.0
 * @description 配制文件是否开始使用
 * @date 2022/8/12
 */
@Configuration
@EnableConfigurationProperties({
        HigestAuthorityProperties.class,
})
public class PropertiesConfig {
}

1.5、重写loadUserByUsername方法

/**
 * @author 木字楠
 * @version 1.0
 * @description 自定义服务实现
 * @date 2022/8/12
 */
@Service
@RequiredArgsConstructor
public class UserDetailsServiceImpl implements UserDetailsService {

    @Resource
    private HttpServletRequest request;
    private final UserAuthService userAuthService;
    private final UserInfoService userInfoService;
    private final RoleService roleService;
    private final MenuService menuService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserAuth userAuth = usernamePasswordCheck(username);
        return convertToUser(request, userAuth);
    }

    /**
     * 用户数据转护
     *
     * @param request  request
     * @param userAuth 用户权限信息
     * @return {@link User} 用户信息
     */
    private User convertToUser(HttpServletRequest request, UserAuth userAuth) {
        User user = BeanCopyUtil.copyObject(userAuth, User.class);
        // 查询用户基础信息
        UserInfo userInfo = userInfoService.getOne(new LambdaQueryWrapper<UserInfo>().eq(UserInfo::getId, userAuth.getUserInfoId()));

        //region 获取用户Ip相关信息
        String ipAddress = IpUtil.getIpAddress(request);
        String ipSource = IpUtil.getIpSource(ipAddress);
        UserAgent userAgent = IpUtil.getUserAgent(request);
        //endregion

        //region 获取用户权限信息
        Set<String> permisstionSet = new HashSet<>(99);
        Role role = roleService.getOne(new LambdaQueryWrapper<Role>().eq(Role::getId, userAuth.getUserRoleId()));
        if (null != role) {
            permisstionSet = menuService.getUserPermissionList(role);
        }
        //endregion

        //数据封装
        String visitor = "游客";
        user.setNickname(userInfo.getNickname());
        user.setAvatar(userInfo.getAvatar());
        user.setGender(GenderEnum.getGenderValueByCode(userInfo.getGender()));
        user.setEmail(userInfo.getEmail());
        user.setPersonIntro(user.getPersonIntro());
        user.setIpAddress(ipAddress);
        user.setIpSource(ipSource);
        user.setGmtCreate(userInfo.getGmtCreate());
        user.setGmtUpdate(userInfo.getGmtUpdate());
        user.setLastLoginTime(userInfo.getLastLoginTime());
        user.setRole(null == role ? visitor : role.getRoleName());
        user.setPermissionList(permisstionSet);
        user.setOs(userAgent.getOperatingSystem().getName());
        user.setBrower(userAgent.getBrowser().getName());

        return user;
    }

    /**
     * 用户名密码校验
     */
    private UserAuth usernamePasswordCheck(String username) {
        // 用户名非空校验
        if (StringUtils.isEmpty(username)) {
            throw new BaseException(HttpCodeEnum.USERNAME_CAN_NOT_BE_EMPTY.getMessage());
        }

        // 查询用户信息
        UserAuth userAuth = userAuthService.getOne(new LambdaQueryWrapper<UserAuth>().eq(UserAuth::getUsername, username)
                .eq(UserAuth::getIsDisabled, SystemConstant.NOT_DISABLED)
                .eq(UserAuth::getIsDeleted, SystemConstant.NOT_DELETED));

        if (null == userAuth) {
            throw new BaseException(HttpCodeEnum.USERNAME_OR_PASSWORD_ERROR.getMessage());
        }

        return userAuth;
    }

}

1.6、自定义匿名访问注解

自定义匿名访问注解,届时我们会使用SpringSecurity拦截所有请求,未登录用户访问接口时将会统一返回 请登陆后再进行访问!,而带有匿名注解的接口将会被放行,无论用户是否登录,都可以正常访问。

/**
 * @author 木字楠
 * @version 1.0
 * @description 匿名访问注解
 * @date 2022/8/12
 */
public @interface Anonymous {
}

    private final ApplicationContext applicationContext;
    /**
     * 查找可以匿名访问的接口
     *
     * @return 匿名访问接口集合
     */
    private Set<String> listAnonymous() {
        Map<RequestMappingInfo, HandlerMethod> handlerMethods =
                applicationContext.getBean(RequestMappingHandlerMapping.class).getHandlerMethods();
        Set<String> anonymousUrls = new HashSet<>();
        for (Map.Entry<RequestMappingInfo, HandlerMethod> infoEntry : handlerMethods.entrySet()) {
            HandlerMethod handlerMethod = infoEntry.getValue();
            AnonymousAccess anonymousAccess = handlerMethod.getMethodAnnotation(AnonymousAccess.class);
            if (anonymousAccess != null) {
                assert infoEntry.getKey().getPatternsCondition() != null;
                anonymousUrls.addAll(infoEntry.getKey().getPatternsCondition().getPatterns());
            }
        }
       System.out.println("可以匿名访问的url:{}", anonymousUrls);
        return anonymousUrls;
    }

1.8、编写SpringSecurity配制类

自定义配制类继承WebSecurityConfigurerAdapter,并且重写其中的三个config方法

在这里插入图片描述
在这里插入图片描述

public void configure(WebSecurity web) 内部重新实现,主要放行静态资源

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().mvcMatchers(
                "/js/**", "/css/**", "/img/**", "/fonts/**",
                "/", "/index.html", "/favicon.ico", "/doc.html",
                "/swagger-ui.html", "/webjars/**", "/swagger-resources/**", "/v3/**");
    }

protected void configure(AuthenticationManagerBuilder auth) 内部重新实现,指定UserDetailsService执行方式以及密码加密方式

    private final UserDetailsServiceImpl userDetailsService;
    
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
    }

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/100164.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Polynomial Round 2022 (Div. 1 + Div. 2, Rated, Prizes!) A-C

比赛链接 目录 A. Add Plus Minus Sign 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; B. Coloring 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; C. Ice and Fire 题意&#xff1a; 思路&#xff1a; 代码&#xff1a; A. Add Plus Minus Sign 题意…

半导体芯片制造过程可以用哪种测量仪器

近年来&#xff0c;面对持续高涨的芯片需求&#xff0c;半导体行业生产迎来了高难度挑战——对芯片工艺要求更精细&#xff0c;从5nm到3nm&#xff0c;甚至是2nm。“先进封装”的提出&#xff0c;是对技术的新要求&#xff0c;也是对封装工艺中材料和设备的全新考验。 芯片身上…

节点电力市场生产商的战略竞标:凸松弛方法(Matlab实现)

目录 1 电力市场 1.1 什么是电力市场 1.2 电力市场发展历程 1.3 对传统电力系统理论的挑战 2 节点电力市场生产商的战略竞标&#xff1a;凸松弛方法 2.1 简介 2 Matlab代码 1 电力市场 1.1 什么是电力市场 市场&#xff1a;商品交换(交换商品的过程称交易)关系的总和 …

pikachu靶场验证码绕过详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是pikachu靶场验证码绕过详解。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对…

endo-BCN-PEG3-Biotin,endo-BCN三聚乙二醇-生物素

【中文名称】endo-BCN三聚乙二醇-生物素 【英文名称】 endo-BCN-PEG3-Biotin&#xff0c;BCN-PEG3-Biotin (endo) 【CAS号】1263166-92-2 【分子式】C29H46N4O7S 【分子量】594.77 【基团部分】BCN 【纯度标准】95% 【外观颜色】 白色固体 &#xff08;具体由其分子量大小决定…

MyBatis学习 | 简介HelloWord

文章目录一、简介二、HelloWord2.1 环境搭建2.2 创建全局配置文件2.3 创建工具类2.4 创建数据库表和对应的JavaBean2.5 创建SQL映射文件2.6 非接口式与接口式编程2.6.1 非接口式编程2.6.2 接口式编程⭐2.7 简单总结学习地址&#x1f517; https://www.bilibili.com/video/BV1mW…

动态规划问题——换钱的方法数

题目&#xff1a; 给定数组arr&#xff0c;arr中所有的值都为正数且不重复。每个值代表一种面值的货币&#xff0c;每种面值的货币可以使用任意张&#xff0c;再给定一个整数aim&#xff0c;代表要找的钱数&#xff0c;求换钱有多少种方法。 举例&#xff1a; arr [5, 10, 2…

【PCL1.11.0+win10+vs2019】环境配置/ 点云格式转换及可视化

文章目录一、安装1.1 下载PCL1.2 安装PCL1.3 安装OSGeo4W二、配置2.1 配置环境变量2.2 配置VS2019三、点云格式转换以及可视化参考一、安装 1.1 下载PCL 首先我们需要下载pcl1.11.0 &#xff0c;这个版本与vs2019对应。 有两种下载方法&#xff1a;百度网盘、官网下载。二选一…

docker原理及服务编排

一、什么是docker Docker 是一个开源项目&#xff0c;诞生于2013年初&#xff0c;最初是dotCloud公司内部的一个业余项目。它基于Google公司推出的Go语言实现。项目后来加入了Linux基金会&#xff0c;遵从了Apache 2.0协议&#xff0c;项目代码在GitHub上进行维护。 Docker 项…

【毕业设计_课程设计】基于Spark网易云音乐数据分析

文章目录0 项目说明1 系统模块2 分析内容3 界面展示4 项目工程0 项目说明 基于Spark网易云音乐数据分析 提示&#xff1a;适合用于课程设计或毕业设计&#xff0c;工作量达标&#xff0c;源码开放 1 系统模块 包含爬虫,Scala代码,Spark,Hadoop,ElasticSearch,logstash,Flume…

基于ChatGPT实现微信智能机器人

ChatGPT近期以强大的对话和信息整合能力风靡全网&#xff0c;可以写代码、改论文、讲故事&#xff0c;几乎无所不能&#xff0c;这让人不禁有个大胆的想法&#xff0c;能否用他的对话模型把我们的微信打造成一个智能机器人&#xff0c;可以在与好友对话中给出意想不到的回应&am…

汇编语言笔记——接口技术与编程

文章目录传送门储存系统与技术材料高速储存器缓冲储存器&#xff08;Cache&#xff09;材料&#xff0c;局部性&#xff0c;访问方式Cache全相联映射Cache交换与一致性单核CPU一致性处理多核CPU的MESI协议主储存器&#xff08;内存&#xff09;主要技术指标容量带宽内存模组与内…

【JavaWeb】Servlet

Servlet简介 Servlet是sun公司开发动态web的一门技术Sun在这些API中提供一个接口叫做&#xff1a;Servlet&#xff0c;如果想开发一个Servlet程序&#xff0c;需要编写一个类&#xff0c;实现Servlet接口把开发好的Java类部署到web服务器中 把实现了Servlet接口的Java程序叫做…

【Anime.js】——Anime.js源码核心理解

一、Anime.js整体结构 Anime.js的强大之处在于代码量非常少&#xff0c;但功能却非常强大。让我们一起来探索Anime.js源码的核心吧~ Anime.js之所以能如此强大主要是因为它的代码结构设计的非常巧妙合理&#xff0c;所以我们想要掌握Anime.js的核心&#xff0c;首先我们要了解…

Linux内核基础篇——动态输出调试

文章目录配置内核编译选项debugfs文件系统挂载动态输出使用实际案例动态输出&#xff08;dynamic print&#xff09;是内核子系统开发者最喜欢的输出技术之一。 上篇说到printk调试&#xff0c;但printk是全局的&#xff0c;只能设置输出等级。而动态输出可以动态选择打开某个…

Tensorflow Serving部署推荐模型

Tensorflow Serving部署推荐模型 1、找到当前模型中定义的variables&#xff0c;并在此定义一个saver用于保存模型参数 def saveVariables(self):variables_dict {}variables_dict[self.user_embedding.op.name] self.user_embeddingvariables_dict[self.item_embedding.op…

【LeetCode】1971. 寻找图中是否存在路径

题目描述 有一个具有 n 个顶点的 双向 图&#xff0c;其中每个顶点标记从 0 到 n - 1&#xff08;包含 0 和 n - 1&#xff09;。图中的边用一个二维整数数组 edges 表示&#xff0c;其中 edges[i] [ui, vi] 表示顶点 ui 和顶点 vi 之间的双向边。 每个顶点对由 最多一条 边连…

犀牛插件开发-基础核心-技术概览-总体架构-教程

文章目录1.概述2.基础核心2.1.C Rhino 核心2.2.openNURBS2.3.C SDK3.C Stack3.1.C Plugins3.2.RhinoScript4.NET Stack4.1.C API4.2.NET Framework4.3.RhinoCommon4.4.Eto4.5.net插件4.6.Grasshopper组件4.7.Python脚本5.相关主题1.概述 《Rhinoceros》由许多层组成——用多种…

细说OA系统的繁荣发展

改革开放以来&#xff0c;科技发展突飞猛进&#xff0c;我们生活的方方面面都受到了巨大影响。随着信息化时代的到来&#xff0c;企业的办公方式也发生了巨大的改变&#xff0c;OA系统随之走进了大众的视野。细数这四十几年&#xff0c;OA办公系统已经由一个异想天开的想法变成…

centos7.8离线安装pg和postgis

安装包下载地址&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1MxJc-5Ws6OPTRAoC-2srJw 提取码&#xff1a;is2q 1.centos7.8 离线安装pg操作步骤 这里基于centos7.8空白系统操作实践写的文档&#xff0c;系统一致的情况下可以照搬教程操作安装&#xff0c;镜像为…