java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > SpringSecurity自定义数据源

SpringSecurity实现自定义数据源实战指南

作者:️X️

本文给大家介绍SpringSecurity实现自定义数据源的相关知识,本文通过实例代码给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧

Spring Security简介

Java中的安全框架通常是指解决Web应用安全问题的框架。自行实现Web应用的安全性并不容易,需要考虑不同的认证和授权机制、网络关键数据传输加密等多方面的问题。
Java中常用的安全框架有Spring Security和Shiro,这两个安全框架都提供了强大功能,可以很容易实现Web应用的很多安全防护。下面对这两个安全框架的特点进行讲解
Spring Security是Spring生态系统中重要的一员,是一个基于AOP思想和Servlet过滤器实现的安全框架,它提供了完善的认证机制和方法级的授权功能,是一款非常优秀的权限管理框架。

在进行安全管理的过程中都涉及权限管理的两个重要概念:Authentication(认证)
和Authorization(授权)。权限管理是指根据系统设置的安全规则或者安全策略,用户可以访问且只能访问自己被授权的资源。
实现权限管理通常需要三个对象,分别为用户、角色、权限,这三个对象的说明如下。

一、SQL数据表的设计

-- 创建用户表
CREATE TABLE `user` (
  -- 主键id,自增
  `id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '用户id',
  -- 用户名字段
  `username` VARCHAR(32) DEFAULT NULL COMMENT '用户名',
  -- 密码字段(建议存储加密后的密码)
  `password` VARCHAR(255) DEFAULT NULL COMMENT '密码',
  -- 账户启用状态:1=启用,0=禁用
  `enabled` TINYINT(1) DEFAULT NULL COMMENT '是否可用',
  -- 账户未过期标志:1=未过期,0=已过期
  `accountNonExpired` TINYINT(1) DEFAULT NULL COMMENT '账户过期',
  -- 账户未锁定标志:1=未锁定,0=已锁定  
  `accountNonLocked` TINYINT(1) DEFAULT NULL COMMENT '账户锁定',
  -- 凭证未过期标志:1=未过期,0=已过期
  `credentialsNonExpired` TINYINT(1) DEFAULT NULL COMMENT '凭证过期',
  -- 设置主键
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 创建角色表(使用roles避免与MySQL关键字冲突)
CREATE TABLE `roles` (
  -- 主键id,自增
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  -- 角色英文名,如ROLE_ADMIN
  `name` VARCHAR(32) DEFAULT NULL,
  -- 角色中文名,如管理员
  `name_zh` VARCHAR(32) DEFAULT NULL,
  -- 设置主键
  PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- 创建用户角色关联表(多对多关系)
CREATE TABLE `user_role` (
  -- 主键id,自增
  `id` INT(11) NOT NULL AUTO_INCREMENT,
  -- 用户id,关联user表
  `uid` INT(11) DEFAULT NULL,
  -- 角色id,关联roles表
  `rid` INT(11) DEFAULT NULL,
  -- 设置主键
  PRIMARY KEY (`id`),
  -- 为uid字段创建索引,提高查询效率
  KEY `uid` (`uid`),
  -- 为rid字段创建索引,提高查询效率
  KEY `rid` (`rid`),
  -- 外键约束:uid引用user表的id字段
  CONSTRAINT `user_role_ibfk_1` FOREIGN KEY (`uid`) REFERENCES `user` (`id`),
  -- 外键约束:rid引用roles表的id字段
  CONSTRAINT `user_role_ibfk_2` FOREIGN KEY (`rid`) REFERENCES `roles` (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8;
-- ==================== 第一步:插入用户数据 ====================
-- 插入3个测试用户
INSERT INTO `user` (
    `username`, 
    `password`, 
    `enabled`, 
    `accountNonExpired`, 
    `accountNonLocked`, 
    `credentialsNonExpired`
) VALUES 
-- 管理员用户:全部状态正常
('admin', 'admin123', 1, 1, 1, 1),
-- 普通用户:正常可用
('zhangsan', '123456', 1, 1, 1, 1),
-- 被禁用的用户:用于测试禁用功能
('lisi', '123456', 0, 1, 1, 1);
-- ==================== 第二步:插入角色数据 ====================
-- 插入几个常用角色
INSERT INTO `roles` (`name`, `name_zh`) VALUES 
('ROLE_ADMIN', '管理员'),
('ROLE_USER', '普通用户'),
('ROLE_GUEST', '访客');
-- ==================== 第三步:插入用户角色关联 ====================
-- 给用户分配角色
INSERT INTO `user_role` (`uid`, `rid`) VALUES 
-- admin用户:同时拥有管理员和普通用户角色
(1, 1),  -- admin -> ROLE_ADMIN
(1, 2),  -- admin -> ROLE_USER
-- zhangsan用户:只有普通用户角色
(2, 2),  -- zhangsan -> ROLE_USER
-- lisi用户:只有访客角色
(3, 3);  -- lisi -> ROLE_GUEST

二、引入Maven依赖

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

三、配置yml文件

spring:
  application:
    name: SpringSecurity
  datasource:
    url: jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: password
    driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
  mapper-locations: com.example.springsecurity.mapper/**/*.xml

四、编写实体类、mapper.xml、mapper层

package com.example.springsecurity.entity;
import lombok.*;
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class Roles {
    private Integer id;
    private String name;
    private String nameZh;
}
package com.example.springsecurity.entity;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import java.util.*;
@ToString
// 自定义用户User
public class User implements UserDetails {/*这里继承UserDetails是因为SpringSecurity低层只认这个,相当于不良人只认大帅不认令牌*/
    private Integer id; // 用户id
    private String username;    // 用户名
    private String password;    // 密码
    private boolean enabled;    // 是否可用
    private boolean accountNonExpired;  // 账户过期
    private boolean accountNonLocked;   // 账户锁定
    private boolean credentialsNonExpired;  // 凭证过期
    private List<Roles> roles = new ArrayList<>();   // 用户角色信息
    // 返回权限信息
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        Set<SimpleGrantedAuthority> authorities = new HashSet<>();
        roles.forEach(role -> {
            SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role.getName());
            authorities.add(simpleGrantedAuthority);
        });
        return authorities;
    }
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return accountNonExpired;
    }
    @Override
    public boolean isAccountNonLocked() {
        return accountNonLocked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return credentialsNonExpired;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }
    public void setAccountNonExpired(boolean accountNonExpired) {
        this.accountNonExpired = accountNonExpired;
    }
    public void setAccountNonLocked(boolean accountNonLocked) {
        this.accountNonLocked = accountNonLocked;
    }
    public void setCredentialsNonExpired(boolean credentialsNonExpired) {
        this.credentialsNonExpired = credentialsNonExpired;
    }
    public void setRoles(List<Roles> roles) {
        this.roles = roles;
    }
    public Integer getId() {
        return id;
    }
    public List<Roles> getRoles() {
        return roles;
    }
}
<?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.example.springsecurity.mapper.RolesMapper">
    <select id="queryRolesByName" resultType="com.example.springsecurity.entity.Roles">
            select
                r.id,
                r.name,
                r.name_zh
            from
                roles r,user_role `ur`
            where
                r.id = `ur`.rid
              and
                ur.uid = #{uid}
    </select>
</mapper>
<?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.example.springsecurity.mapper.UserMapper">
    <select id="queryUserByName" resultType="com.example.springsecurity.entity.User">
        select * from user <if test="username !=null and username !=''">
        <where>
            username = #{username}
        </where>
         limit  1
    </if>
    </select>
</mapper>
public interface RolesMapper {
    List<Roles> queryRolesByName(@Param("uid") Integer uid);
}
public interface UserMapper {
    User queryUserByName(@Param("username") String username);
}

五、编写service层

@Service
@RequiredArgsConstructor//lombok自动生成构造函数
public class MyDetailsService  implements UserDetailsService {
    private final UserMapper userMapper;
    private final RolesMapper rolesMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        System.out.println("username:========"+username);
        User user = userMapper.queryUserByName(username);
        if(ObjectUtil.isEmpty(user))
        {
            throw new UsernameNotFoundException("用户不存在");
        }
        //这里因为没有配置密码格式,后台数据库如果是明文的话,就需要用这个暂时“过渡”一下
        user.setPassword("{noop}" + user.getPassword());
        List<Roles> roles = rolesMapper.queryRolesByName(user.getId());
        user.setRoles(roles);
        return user;
    }
}

六、测试运行

到此这篇关于SpringSecurity实现自定义数据源的文章就介绍到这了,更多相关SpringSecurity自定义数据源内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文