SpringBoot浅析安全管理之基于数据库认证

目录
  • 1. 设计数据表
  • 2. 创建项目
  • 3. 配置数据库
  • 4. 创建实体类
  • 5. 创建UserService
  • 6. 配置Spring Security
  • 7.创建Controller
  • 8. 测试

1. 设计数据表

用户表、角色表、用户角色关联表

建表语句

CREATE TABLE `role` (
  `id` int(11) NOT NULL,
  `name` varchar(32) DEFAULT NULL,
  `nameZh` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user` (
  `id` int(11) NOT NULL,
  `username` varchar(32) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `enabled` varchar(1) DEFAULT NULL,
  `locked` varchar(1) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `user_role` (
  `id` int(11) NOT NULL,
  `uid` int(11) DEFAULT NULL,
  `rid` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

初始化数据

注意:角色名有一个默认的前缀 ROLE_

INSERT INTO `user`(`id`, `username`, `password`, `enabled`, `locked`) VALUES (1, 'root', '$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e', '1', '0');
INSERT INTO `user`(`id`, `username`, `password`, `enabled`, `locked`) VALUES (2, 'admin', '$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e', '1', '0');
INSERT INTO `user`(`id`, `username`, `password`, `enabled`, `locked`) VALUES (3, 'tangsan', '$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e', '1', '0');
INSERT INTO `role`(`id`, `name`, `nameZh`) VALUES (1, 'ROLE_dba', '数据库管理员');
INSERT INTO `role`(`id`, `name`, `nameZh`) VALUES (2, 'ROLE_admin', '系统管理员');
INSERT INTO `role`(`id`, `name`, `nameZh`) VALUES (3, 'ROLE_user', '普通用户');
INSERT INTO `user_role`(`id`, `uid`, `rid`) VALUES (1, 1, 1);
INSERT INTO `user_role`(`id`, `uid`, `rid`) VALUES (2, 1, 2);
INSERT INTO `user_role`(`id`, `uid`, `rid`) VALUES (3, 2, 2);
INSERT INTO `user_role`(`id`, `uid`, `rid`) VALUES (4, 3, 3);

2. 创建项目

MyBatis 灵活,JPA 便利,此处选择前者,创建 Spring Boot Web 项目添加如下依赖:

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
  <groupId>org.mybatis.spring.boot</groupId>
  <artifactId>mybatis-spring-boot-starter</artifactId>
  <version>1.3.2</version>
</dependency>
<dependency>
  <groupId>mysql</groupId>
  <artifactId>mysql-connector-java</artifactId>
  <scope>runtime</scope>
</dependency>
<dependency>
  <groupId>com.alibaba</groupId>
  <artifactId>druid</artifactId>
  <version>1.1.10</version>
</dependency>

3. 配置数据库

在 application.properties 中进行数据连接配置

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.url=jdbc:mysql://localhost:3306/jpa

4. 创建实体类

Role

public class Role {
    private Integer id;
    private String name;
    private String nameZh;
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getNameZh() {
        return nameZh;
    }
    public void setNameZh(String nameZh) {
        this.nameZh = nameZh;
    }
}

User

public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<Role> roles;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return authorities;
    }
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return !locked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    public Integer getId() {
        return id;
    }
    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 Boolean getEnabled() {
       return enabled;
    }
    public void setEnabled(Boolean enabled) {
        this.enabled = enabled;
    }
    public Boolean getLocked() {
        return locked;
    }
    public void setLocked(Boolean locked) {
        this.locked = locked;
    }
    public List<Role> getRoles() {
        return roles;
    }
    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
}

代码解释:

用户实体类需要实现 UserDetails 接口,并且实现该接口中的 7 个方法

| 方法名 | 解释 |

| — | — |

| getAuthorities() | 获取当前用户对象所具有的角色信息 |

| getPassword() | 获取当前用户对象的密码 |

| getUsername() | 获取当前用户对象的用户名 |

| isAccountNonExpired() | 当前账号是否未过期 |

| isAccountNonLocked() | 当前账号是否未锁定 |

| isCredentialsNonExpired() | 当前账号密码是否未过期 |

| isEnabled() | 当前账号是否可用 |

用户根据实际情况设置这 7 个方法的返回值。因为默认情况下不需要开发者自己进行密码角色等信息的比对,开发者只需要提供相关信息即可,例如 getPassword() 方法返回的密码和用户输入的密码不匹配,会自动抛出 BadCredentialsException 异常,isAccountNonExpired() 方法返回了 false ,会自动抛出 AccountExpiredException 异常,因此对开发者而言,只需要按照数据库中的数据在这里返回相应的配置即可。此处因为数据库中只有 enabled 和 locked 字段,故帐号未过期和密码未过期两个方法都返回 true

getAuthorities() 用来获取当前用户所具有的角色信息,此处用户所具有的角色存储在 roles 属性中,因此该方法直接遍历 roles 属性,然后构造 SimpleGrantedAuthority 集合并返回

5. 创建UserService

@Service
public class UserService implements UserDetailsService {
    @Autowired
    UserMapper userMapper;
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.loadUserByUsername(username);
        if (user == null) {
            throw new UsernameNotFoundException("账户不存在!");
        }
        user.setRoles(userMapper.getUserRolesByUid(user.getId()));
        return user;
    }
}

代码解释:

  • 定义 UserService 实现 UserDetailsService 接口,并实现该接口中的 loadUserByUsername 方法,该方法的参数就是用户登录时输入的用户名,通过用户名去数据库中查找用户,如果没有查询到用户,就抛出一个账号不存在的异常,如果查找到了用户,就继续查询该用户所具有的角色信息,并将获取到的 user 对象返回,再由系统提供的 DaoAuthenticationProvider 类去比对密码是否正确
  • loadUserByUsername 方法将在用户登录时自动调用

涉及到的 UserMapper 和 UserMapper.xml 如下

@Mapper
public interface UserMapper {
    User loadUserByUsername(String username);
    List<Role> getUserRolesByUid(Integer id);
}
<?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="org.sang.mapper.UserMapper">
    <select id="loadUserByUsername" resultType="org.sang.model.User">
        select * from user where username=#{username}
    </select>
    <select id="getUserRolesByUid" resultType="org.sang.model.Role">
        select * from role r,user_role ur where r.id=ur.rid and ur.uid=#{id}
    </select>
</mapper>

6. 配置Spring Security

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    UserService userService;
    @Bean
    PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService);
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers("/admin/**").hasRole("admin")
                .antMatchers("/db/**").hasRole("dba")
                .antMatchers("/user/**").hasRole("user")
                .anyRequest().authenticated()
                .and()
                .formLogin()
                .loginProcessingUrl("/login").permitAll()
                .and()
                .csrf().disable();
    }
}

此处的配置与上篇介绍的一致,唯一不同的是没有配置内存用户,而是将刚刚创建好的 UserService 配置到 AuthenticationManagerBuilder 中。

7.创建Controller

@RestController
public class HelloController {
    @GetMapping("/admin/hello")
    public String admin() {
        return "hello admin";
    }
    @GetMapping("/db/hello")
    public String dba() {
        return "hello dba";
    }
    @GetMapping("/user/hello")
    public String user() {
        return "hello user";
    }
}

8. 测试

登录 admin 用户,访问 /admin/hello,报了以下错误

Invalid bound statement (not found)

pom.xml 新增以下配置

<build>
  <resources>
    <resource>
      <directory>src/main/java</directory>
      <includes>
        <include>**/*.xml</include>
      </includes>
    </resource>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
  </resources>
</build>

再次登录访问 /admin/hello,报了以下错误

Caused by: org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: Illegal overloaded getter method with ambiguous type for property enabled in class class org.sang.model.User. This breaks the JavaBeans specification and can cause unpredictable results.

去掉 User 实体类中 enabled 属性的 get set 方法,如下

public class User implements UserDetails {
    private Integer id;
    private String username;
    private String password;
    private Boolean enabled;
    private Boolean locked;
    private List<Role> roles;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        List<SimpleGrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }
        return authorities;
    }
    @Override
    public String getPassword() {
        return password;
    }
    @Override
    public String getUsername() {
        return username;
    }
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }
    @Override
    public boolean isAccountNonLocked() {
        return !locked;
    }
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }
    @Override
    public boolean isEnabled() {
        return enabled;
    }
    public Integer getId() {
        return id;
    }
    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 Boolean getLocked() {
        return locked;
    }
    public void setLocked(Boolean locked) {
        this.locked = locked;
    }
    public List<Role> getRoles() {
        return roles;
    }
    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }
}

再次登录访问 /admin/hello

访问 /db/hello

访问 /user/hello

到此这篇关于SpringBoot浅析安全管理之基于数据库认证的文章就介绍到这了,更多相关SpringBoot数据库认证内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Spring boot整合security详解

    目录 前言 配置依赖 用户配置 1.内存用户存储 2.数据库用户存储 3.LDAP用户存储 4.自定义用户存储 拦截配置 前言 在进行框架选型时最常用的选择就是在Spring security 和Shiro中进行抉择,Spring security 和 shiro 一样,都具有认证.授权.加密等用于权限管理的功能.但是对于Springboot而言,Spring Security比Shiro更合适一些,他们都是Spring生态里的内容,并且在使用上Spring boot只需要引入Security就

  • Springboot详解整合SpringSecurity实现全过程

    目录 使用Basic认证模式 使用form表形式登录 实现权限控制 自定义登录页面 结合数据库实现RBAC权限模型权限控制 java代码 动态绑定数据库所有权限 使用Basic认证模式 1.maven依赖 <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.

  • SpringBoot浅析安全管理之Shiro框架

    目录 Shiro 简介 整合 Shiro 1. 创建项目 2. Shiro基本配置 3. 测试 Shiro 简介 Apache Shiro 是一个开源的轻量级的 Java 安全框架,它提供身份验证.授权.密码管理以及会话管理等功能.相对于 Spring Security ,Shiro 框架更加直观.易用,同时也能提供健壮的安全性. 在传统的 SSM 框架中,手动整合 Shiro 的配置步骤还是比较多的,针对 Spring Boot ,Shiro 官方提供了 shiro-spring-boot-w

  • SpringBoot浅析安全管理之Spring Security配置

    目录 Spring Security 的基本配置 基本用法 1. 创建项目添加依赖 2. 添加 hello 接口 3. 启动项目测试 配置用户名和密码 基于内存的认证 HttpSecurity 登录表单详细配置 注销登录配置 多个 HttpSecurity 密码加密 1. 为什么要加密 2. 加密方案 3. 实践 方法安全 在 Java 开发领域常见的安全框架有 Shiro 和 Spring Security.Shiro 是一个轻量级的安全管理框架,提供了认证.授权.会话管理.密码管理.缓存管理

  • SpringBoot2.0 整合 SpringSecurity 框架实现用户权限安全管理方法

    一.Security简介 1.基础概念 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架.它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring的IOC,DI,AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为安全控制编写大量重复代码的工作. 2.核心API解读 1).SecurityContextHolder 最基本的对象,保存着当前会话用户认证,权限,鉴权等核心数据.Secu

  • SpringBoot整合Security安全框架实现控制权限

    目录 一.前言 介绍: 官网: 优缺点: 案例: 二.环境准备 2.1.数据库表 2.2.导入依赖 2.3.配置文件 2.4.WebSecurityConfig Security的主要配置类: 2.5.Security身份验证 2.6.Security授权 2.7.UserDetailsService 2.7.MacLoginUrlAuthenticationEntryPoint 2.8.MyAccessDeniedHandler 2.9.MyLogoutSuccessHandler 2.10.

  • SpringBoot整合SpringSecurity实现JWT认证的项目实践

    目录 前言 1.创建SpringBoot工程 2.导入SpringSecurity与JWT的相关依赖 3.定义SpringSecurity需要的基础处理类 4. 构建JWT token工具类 5.实现token验证的过滤器 6. SpringSecurity的关键配置 7. 编写Controller进行测试 前言 微服务架构,前后端分离目前已成为互联网项目开发的业界标准,其核心思想就是前端(APP.小程序.H5页面等)通过调用后端的API接口,提交及返回JSON数据进行交互.在前后端分离项目中,

  • SpringBoot+SpringSecurity+jwt实现验证

    目录 环境 目录结构信息 记录一下使用springSecurity实现jwt的授权方法,这方法可以实现权限的基本认证.当然这个案例还有许多的问题,不过还是先记录一下.其他功能以后在补充. 建议工程创建流程 创建 JwtTokenUtils 创建 jwtAccessDeniedHandler 和 JwtAuthenticationEntryPoint 创建 UserDetailsServiceImpl 创建 JwtAuthenticationFilter 配置 Security信息 启动类的信息

  • SpringBoot浅析安全管理之OAuth2框架

    目录 OAuth2简介 OAuth2角色 OAuth2授权流程 授权模式 实践 1. 创建项目添加依赖 2. 配置授权服务器 3. 配置资源服务器 4. 配置 Security 5. 验证测试 OAuth2简介 OAuth 是一个开放标准,该标准允许用户让第三方应用访问该用户在某一网站上存储的私密资源(如头像.照片.视频等),而在这个过程中无须将用户名和密码提供给第三方应用. 实现这一功能是通过一个令牌(token),而不是用户名和密码来访问他们存放在特定服务提供者的数据.每一个令牌授权一个特定

  • SpringBoot浅析安全管理之基于数据库认证

    目录 1. 设计数据表 2. 创建项目 3. 配置数据库 4. 创建实体类 5. 创建UserService 6. 配置Spring Security 7.创建Controller 8. 测试 1. 设计数据表 用户表.角色表.用户角色关联表 建表语句 CREATE TABLE `role` ( `id` int(11) NOT NULL, `name` varchar(32) DEFAULT NULL, `nameZh` varchar(32) DEFAULT NULL, PRIMARY KE

  • SpringBoot浅析安全管理之高级配置

    目录 角色继承 动态权限配置 1. 数据库设计 2. 自定义FilterInvocationSecurityMetadataSource 3. 自定义 AccessDecisionManager 4. 配置 角色继承 SpringBoot浅析安全管理之基于数据库认证中定义了三种角色,但是这三种角色之间不具备任何关系,一般来说角色之间是有关系的,例如 ROLE_admin 一般既具有 admin 权限,又具有 user 权限.那么如何配置这种角色继承关系呢?只需要开发者在 Spring Secur

  • 基于springboot实现整合shiro实现登录认证以及授权过程解析

    这篇文章主要介绍了基于springboot实现整合shiro实现登录认证以及授权过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.添加shiro的依赖 <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring-boot-web- starter</artifactId> <version&g

  • SpringBoot基于数据库实现定时任务过程解析

    这篇文章主要介绍了SpringBoot基于数据库实现定时任务过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 在我们平时开发的项目中,定时任务基本属于必不可少的功能,那大家都是怎么做的呢?但我知道的大多都是静态定时任务实现. 基于注解来创建定时任务非常简单,只需几行代码便可完成.实现如下: @Configuration @EnableScheduling public class SimpleScheduleTask { //10秒钟执行

  • 一篇文章带你搞定 springsecurity基于数据库的认证(springsecurity整合mybatis)

    一.前期配置 1. 加入依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.10</version> </dependency> <dependency> <groupId>mysql</groupId> &

  • springboot使用JdbcTemplate完成对数据库的增删改查功能

    首先新建一个简单的数据表,通过操作这个数据表来进行演示 DROP TABLE IF EXISTS `items`; CREATE TABLE `items` ( `id` int(11) NOT NULL AUTO_INCREMENT, `title` varchar(255) DEFAULT NULL, `name` varchar(10) DEFAULT NULL, `detail` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE

  • springboot+jwt实现token登陆权限认证的实现

    一 前言 此篇文章的内容也是学习不久,终于到周末有时间码一篇文章分享知识追寻者的粉丝们,学完本篇文章,读者将对token类的登陆认证流程有个全面的了解,可以动态搭建自己的登陆认证过程:对小项目而已是个轻量级的认证机制,符合开发需求: 二 jwt实现登陆认证流程 用户使用账号和面发出post请求 服务器接受到请求后使用私钥创建一个jwt,这边会生成token 服务器返回这个jwt给浏览器 浏览器需要将带有token的jwt放入请求头 每次手到客户端请求,服务器验证该jwt的token 验证成功返回

随机推荐