IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> SpringSecurit权限管理框架系列(四)-Spring Security结合MySQL数据库实现自定义权限认证 -> 正文阅读

[Java知识库]SpringSecurit权限管理框架系列(四)-Spring Security结合MySQL数据库实现自定义权限认证

1、自定义权限认证的实现思路

  • 自定义一个实体类LoginUser用来保存SygUser用户信息以及权限信息Set<String> permissions

  • 让这个LoginUser实体类实现Userdetails接口

  • 自定义的MyUserDetailsServiceImpl类的loadUserByUsername()方法中实现用户信息查询及该用户的权限信息查询

  • 自定义的MyUserDetailsServiceImpl类的loadUserByUsername()方法返回LoginUser实体类对象

2、代码实现以及中间出现的问题的解决方法

2.1 定义LoginUser实体类【初始定义,一会还会儿修改】

自定义登录用户实体类LoginUser如下,让其实现UserDetails接口

package com.yige.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;
import java.util.Set;

/**
 * @Author: karma
 * @Date: 2022/3/21 0021 - 03 - 21 - 16:17
 * @Description: com.yige.pojo
 * @version: 1.0
 */
public class LoginUser implements UserDetails{

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

    /**
     * 用户信息
     */
    private SygUser user;

    public LoginUser() {
    }

    public LoginUser(SygUser user, Set<String> permissions) {
        this.permissions = permissions;
        this.user = user;
    }

    public Set<String> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<String> permissions) {
        this.permissions = permissions;
    }

    public SygUser getUser() {
        return user;
    }

    public void setUser(SygUser user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @JsonIgnore
    @Override
    public String getPassword() {
        return null;
    }

    @Override
    public String getUsername() {
        return null;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonExpired() {
        return false;
    }

    @JsonIgnore
    @Override
    public boolean isAccountNonLocked() {
        return false;
    }

    @JsonIgnore
    @Override
    public boolean isCredentialsNonExpired() {
        return false;
    }

    @JsonIgnore
    @Override
    public boolean isEnabled() {
        return false;
    }
}

2.2 修改MyUserDetailsServiceImpl类

修改loadUserByUsername(String userName)方法的实现逻辑,让其最后返回LoginUser实体类对象,具体实现如下

package com.yige.service.impl;

import com.yige.pojo.LoginUser;
import com.yige.pojo.SygUser;
import com.yige.service.SygUserSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.context.SecurityContextHolder;
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.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;

@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SygUserSerivce userSerivce;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        if(!StringUtils.hasLength(userName)) throw new UsernameNotFoundException("用户名不能为空");
        SygUser sygUser = userSerivce.selectUserByUserName(userName);
        if(null == sygUser) throw new UsernameNotFoundException("用户不存在");
        // 这里我们先不存数据库查权限信息,先给个空值,看看流程可不可以走通
        return createLoginUser(sygUser, new HashSet<String>());
    }

    public UserDetails createLoginUser(SygUser user, Set<String> permissions) {
        return new LoginUser(user, permissions);
    }
}

保存修改,重启项目,进行测试;

2.3 测试中遇到的问题及处理方法

使用账号student001,密码student001进行正常登录测试, 发现报错User account is locked, 这肯定不对,我们的账号是在数据库查出来的,状态肯定是正常启用的,没有被锁定,这是怎么回事?先说说怎么解决,后面再说为什么会这样

2.3.1 User account is locked异常

在这里插入图片描述
`User account is locked异常解决方法

修改你的实体类LoginUserisAccountNonLocked方法返回值为true即可
在这里插入图片描述修改之后
在这里插入图片描述
重新启动项目,再次测试

2.3.2 User is disabled异常

在这里插入图片描述
`User is disabled异常解决方法

修改你的实体类LoginUserisEnabled方法返回值为true即可
在这里插入图片描述
重新启动项目,再次测试

2.3.3 User account has expired异常

在这里插入图片描述
`User account has expired异常解决方法

修改你的实体类LoginUserisAccountNonExpired方法返回值为true即可
在这里插入图片描述
重新启动项目,再次测试

2.3.4 Bad credentials异常

在这里插入图片描述
Bad credentials异常解决方法

修改你的实体类LoginUserisCredentialsNonExpired方法返回值为true即可
在这里插入图片描述
重新启动项目,再次测试,

2.3.5 Empty encoded password异常

发现还是报错Bad credentials,但是后台console打印了一条warn日志,说是Empty encoded password,说明我们提供的userDetails的实现类实现的getPassword方法无法正常获取到用户密码, 怎么处理?
在这里插入图片描述
Empty encoded password异常解决方法

修改你的实体类LoginUsergetPassword方法返回值为你数据库用户实体类对象的密码即可
在这里插入图片描述
重新启动项目,再次测试
使用账号student001,密码student001进行正常登录测试, 登录成功
使用账号manager,密码manager进行正常登录测试, 登录成功, OK, 基本流程走通
在这里插入图片描述

2.4 所有问题处理完成之后的LoginUser实体类的全貌

package com.yige.pojo;

import com.fasterxml.jackson.annotation.JsonIgnore;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.Collection;
import java.util.Set;

public class LoginUser implements UserDetails {

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

    /**
     * 用户信息
     */
    private SygUser user;

    public LoginUser() {
    }

    public LoginUser(SygUser user, Set<String> permissions) {
        this.permissions = permissions;
        this.user = user;
    }

    public Set<String> getPermissions() {
        return permissions;
    }

    public void setPermissions(Set<String> permissions) {
        this.permissions = permissions;
    }

    public SygUser getUser() {
        return user;
    }

    public void setUser(SygUser user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @JsonIgnore
    @Override
    public String getPassword() {
        return user.getPassword();
    }

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

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

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

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

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

2.5 我是怎么知道修改哪些方法就能解决问题的?

其实一开始我也不知道怎么处理这些问题, 我也觉得很奇怪, 为什么就会报这种错误?
直到我想到LoginUser实现了UserDetails接口, 里面有很多需要子类去实现的方法, 我就去看看了一下UserDetails接口中关于这几个方法的注释, 一下就明白了, 我们一起看看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
以上就是为什么要修改LoginUser实现类那几个重写方法的返回值的原因, 不知道我有没有说清楚,哈哈, 个人理解哈,不喜勿喷~~

3、自定义权限的代码实现

3.1 实现查询用户权限的接口逻辑

  • service层
package com.yige.service;

import com.yige.pojo.SygUser;

import java.util.HashSet;
import java.util.Set;

public interface SygPermissionService {

    /**
     * @description 获取登录用户的菜单数据权限
     * @param user 用户信息
     * @return 菜单权限信息
     */
    public Set<String> getMenuPermission(SygUser user);
}
  • service.impl层
package com.yige.service.impl;

import com.yige.mapper.SygPermissionMapper;
import com.yige.pojo.SygUser;
import com.yige.service.SygPermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashSet;
import java.util.Set;

@Service
public class SygPermissionServiceImpl implements SygPermissionService {

    @Autowired
    private SygPermissionMapper permissionMapper;

    public Set<String> getMenuPermission(SygUser user) {
        Set<String> perms = new HashSet<>();
        perms.addAll(permissionMapper.selectMenuPermsByUserId(user.getUserId()));
        return perms;
    }
}
  • mapper层
package com.yige.mapper;

import org.apache.ibatis.annotations.Param;

import java.util.List;

public interface SygPermissionMapper {

    List<String> selectMenuPermsByUserId(@Param("userId") Long userId);
}
  • SygPermissionMapper.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.yige.mapper.SygPermissionMapper">

    <select id="selectMenuPermsByUserId" resultType="string">
        select
          bm.menu_perms
        from
          bs_user as bu
        left join
          bs_user_role as bur
        on
          bu.user_id = bur.role_id
        left join
          bs_role_permission as brp
        on
          bur.role_id = brp.role_id
        left join
          bs_menu as bm
        on
          bm.menu_id = brp.menu_id
        where
          bu.user_id = #{userId}
  </select>
</mapper>

3.2 修改MyUserDetailsServiceImpl类的实现逻辑

package com.yige.service.impl;

import com.yige.pojo.LoginUser;
import com.yige.pojo.SygUser;
import com.yige.service.SygPermissionService;
import com.yige.service.SygUserSerivce;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.Set;


@Service
public class MyUserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private SygUserSerivce userSerivce;

    @Autowired
    private SygPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        if(!StringUtils.hasLength(userName)) throw new UsernameNotFoundException("用户名不能为空");
        SygUser sygUser = userSerivce.selectUserByUserName(userName);
        if(null == sygUser) throw new UsernameNotFoundException("用户不存在");
        return createLoginUser(sygUser, permissionService.getMenuPermission(sygUser));
    }

    public UserDetails createLoginUser(SygUser user, Set<String> permissions) {
        permissions.stream().forEach(System.out::println);
        return new LoginUser(user, permissions);
    }
}

重新启动项目,再次测试
使用账号student001,密码student001进行正常登录测试, 登录成功
在这里插入图片描述控制台打印用户student001的权限列表
在这里插入图片描述
使用账号manager,密码manager进行正常登录测试, 登录成功
在这里插入图片描述
控制台打印manager用户的权限列表
在这里插入图片描述
至此,自定义权限认证的逻辑就全部实现完成了, 起始回头自己在捋一捋, 会不会发现其实也不太复杂,流程很清晰,实现很简单。喜欢我的文章请多多关注哈, 大家一起进步~

4、下一篇主要内容

下一篇主要研究一下WebSecurityConfigurerAdapter这个配置类以及
自定义配置类SecurityConfig来演示一下Spring security提供的各个接口的的作用以及怎么使用,敬请关注~

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-24 00:21:20  更:2022-03-24 00:25:54 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:27:56-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码