SpringBoot安全管理之基于数据库认证的方法
导读:本文共6615.5字符,通常情况下阅读需要22分钟。同时您也可以点击右侧朗读,来听本文内容。按键盘←(左) →(右) 方向键可以翻页。
摘要:这篇“SpringBoot安全管理之基于数据库认证的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“SpringBoot安全管理之基于数据库认证的方法”文章吧。1. 设计数据表用户表、角色表、用户角色关联表建表语句CREATETABLE`role`(`id`int(11)NOTN... ...
目录
(为您整理了一些要点),点击可以直达。这篇“SpringBoot安全管理之基于数据库认证的方法”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“SpringBoot安全管理之基于数据库认证的方法”文章吧。
1. 设计数据表
用户表、角色表、用户角色关联表
建表语句
CREATETABLE`role`(`id`int(11)NOTNULL,`name`varchar(32)DEFAULTNULL,`nameZh`varchar(32)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE`user`(`id`int(11)NOTNULL,`username`varchar(32)DEFAULTNULL,`password`varchar(255)DEFAULTNULL,`enabled`varchar(1)DEFAULTNULL,`locked`varchar(1)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;CREATETABLE`user_role`(`id`int(11)NOTNULL,`uid`int(11)DEFAULTNULL,`rid`int(11)DEFAULTNULL,PRIMARYKEY(`id`))ENGINE=InnoDBDEFAULTCHARSET=utf8;
初始化数据
注意:角色名有一个默认的前缀 ROLE_
INSERTINTO`user`(`id`,`username`,`password`,`enabled`,`locked`)VALUES(1,'root','$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e','1','0');INSERTINTO`user`(`id`,`username`,`password`,`enabled`,`locked`)VALUES(2,'admin','$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e','1','0');INSERTINTO`user`(`id`,`username`,`password`,`enabled`,`locked`)VALUES(3,'tangsan','$2a$10$x6CBW1qnQqKPIxUSefZN7ebfTEiYNnfzzVjPJzlRhg5XyMzSWoO4e','1','0');INSERTINTO`role`(`id`,`name`,`nameZh`)VALUES(1,'ROLE_dba','数据库管理员');INSERTINTO`role`(`id`,`name`,`nameZh`)VALUES(2,'ROLE_admin','系统管理员');INSERTINTO`role`(`id`,`name`,`nameZh`)VALUES(3,'ROLE_user','普通用户');INSERTINTO`user_role`(`id`,`uid`,`rid`)VALUES(1,1,1);INSERTINTO`user_role`(`id`,`uid`,`rid`)VALUES(2,1,2);INSERTINTO`user_role`(`id`,`uid`,`rid`)VALUES(3,2,2);INSERTINTO`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
publicclassRole{privateIntegerid;privateStringname;privateStringnameZh;publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){this.name=name;}publicStringgetNameZh(){returnnameZh;}publicvoidsetNameZh(StringnameZh){this.nameZh=nameZh;}}
User
publicclassUserimplementsUserDetails{privateIntegerid;privateStringusername;privateStringpassword;privateBooleanenabled;privateBooleanlocked;privateList<Role>roles;@OverridepublicCollection<?extendsGrantedAuthority>getAuthorities(){List<SimpleGrantedAuthority>authorities=newArrayList<>();for(Rolerole:roles){authorities.add(newSimpleGrantedAuthority(role.getName()));}returnauthorities;}@OverridepublicStringgetPassword(){returnpassword;}@OverridepublicStringgetUsername(){returnusername;}@OverridepublicbooleanisAccountNonExpired(){returntrue;}@OverridepublicbooleanisAccountNonLocked(){return!locked;}@OverridepublicbooleanisCredentialsNonExpired(){returntrue;}@OverridepublicbooleanisEnabled(){returnenabled;}publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicvoidsetUsername(Stringusername){this.username=username;}publicvoidsetPassword(Stringpassword){this.password=password;}publicBooleangetEnabled(){returnenabled;}publicvoidsetEnabled(Booleanenabled){this.enabled=enabled;}publicBooleangetLocked(){returnlocked;}publicvoidsetLocked(Booleanlocked){this.locked=locked;}publicList<Role>getRoles(){returnroles;}publicvoidsetRoles(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
@ServicepublicclassUserServiceimplementsUserDetailsService{@AutowiredUserMapperuserMapper;@OverridepublicUserDetailsloadUserByUsername(Stringusername)throwsUsernameNotFoundException{Useruser=userMapper.loadUserByUsername(username);if(user==null){thrownewUsernameNotFoundException("账户不存在!");}user.setRoles(userMapper.getUserRolesByUid(user.getId()));returnuser;}}
代码解释:
定义 UserService 实现 UserDetailsService 接口,并实现该接口中的 loadUserByUsername 方法,该方法的参数就是用户登录时输入的用户名,通过用户名去数据库中查找用户,如果没有查询到用户,就抛出一个账号不存在的异常,如果查找到了用户,就继续查询该用户所具有的角色信息,并将获取到的 user 对象返回,再由系统提供的 DaoAuthenticationProvider 类去比对密码是否正确
loadUserByUsername 方法将在用户登录时自动调用
涉及到的 UserMapper 和 UserMapper.xml 如下
@MapperpublicinterfaceUserMapper{UserloadUserByUsername(Stringusername);List<Role>getUserRolesByUid(Integerid);}
<?xmlversion="1.0"encoding="UTF-8"?><!DOCTYPEmapperPUBLIC"-//mybatis.org//DTDMapper3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mappernamespace="org.sang.mapper.UserMapper"><selectid="loadUserByUsername"resultType="org.sang.model.User">select*fromuserwhereusername=#{username}</select><selectid="getUserRolesByUid"resultType="org.sang.model.Role">select*fromroler,user_roleurwherer.id=ur.ridandur.uid=#{id}</select></mapper>
6. 配置Spring Security
@ConfigurationpublicclassWebSecurityConfigextendsWebSecurityConfigurerAdapter{@AutowiredUserServiceuserService;@BeanPasswordEncoderpasswordEncoder(){returnnewBCryptPasswordEncoder();}@Overrideprotectedvoidconfigure(AuthenticationManagerBuilderauth)throwsException{auth.userDetailsService(userService);}@Overrideprotectedvoidconfigure(HttpSecurityhttp)throwsException{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
@RestControllerpublicclassHelloController{@GetMapping("/admin/hello")publicStringadmin(){return"helloadmin";}@GetMapping("/db/hello")publicStringdba(){return"hellodba";}@GetMapping("/user/hello")publicStringuser(){return"hellouser";}}
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 方法,如下
publicclassUserimplementsUserDetails{privateIntegerid;privateStringusername;privateStringpassword;privateBooleanenabled;privateBooleanlocked;privateList<Role>roles;@OverridepublicCollection<?extendsGrantedAuthority>getAuthorities(){List<SimpleGrantedAuthority>authorities=newArrayList<>();for(Rolerole:roles){authorities.add(newSimpleGrantedAuthority(role.getName()));}returnauthorities;}@OverridepublicStringgetPassword(){returnpassword;}@OverridepublicStringgetUsername(){returnusername;}@OverridepublicbooleanisAccountNonExpired(){returntrue;}@OverridepublicbooleanisAccountNonLocked(){return!locked;}@OverridepublicbooleanisCredentialsNonExpired(){returntrue;}@OverridepublicbooleanisEnabled(){returnenabled;}publicIntegergetId(){returnid;}publicvoidsetId(Integerid){this.id=id;}publicvoidsetUsername(Stringusername){this.username=username;}publicvoidsetPassword(Stringpassword){this.password=password;}publicBooleangetLocked(){returnlocked;}publicvoidsetLocked(Booleanlocked){this.locked=locked;}publicList<Role>getRoles(){returnroles;}publicvoidsetRoles(List<Role>roles){this.roles=roles;}}
再次登录访问 /admin/hello
访问 /db/hello
访问 /user/hello
以上就是关于“SpringBoot安全管理之基于数据库认证的方法”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注亿速云行业资讯频道。
SpringBoot安全管理之基于数据库认证的方法的详细内容,希望对您有所帮助,信息来源于网络。