文章目录
- 1、背景
- 2、相关概念
- 3、Java安全框架的实现
- 4、入门案例
- 4、使用配置文件配置用户名和密码
- 5、基于内存的多用户管理
1、背景
新建个SpringBoot工程,写三个controller,里面有三个接口:
//学生
@RestController
@RequestMapping("/student")
public class StudentController {
@GetMapping("/query")
public String queryInfo(){
return "this is a student,9527";
}
}
//老师
@RestController
@RequestMapping("/teacher")
public class TeacherController {
@GetMapping("/query")
public String queryInfo(){
return "this is a teacher,Mr.L";
}
}
//管理员
@RestController
@RequestMapping("/admin")
public class AdminController {
@GetMapping("/query")
public String queryInfo(){
return "this is a administrator, root";
}
}
启动程序,此时不论是谁,访问这三个接口资源,都能成功返回信息。
curl -X GET localhost:9527/teacher/query
即没有加入安全框架的代码程序,默认所有资源均不受保护,可被随意访问,因此,需要集成安全框架。
2、相关概念
认证:
认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源,常见的用户身份认证的方式有:
- 用户名密码登录
- 二维码登录
- 手机短信登录
- 指纹认证
- 人脸识别
会话:
用户认证通过后,为了避免用户的每次操作都进行认证可将用户的信息保存在会话中。会话就是系统为了保持当前用户的登录状态所提供的机制。直白讲就是别每干一件事就查身份,给你个五年有效期的身份证,你带身上或者我帮你存着,有这个证明,在这期间你就不用再反复认证
常见的实现方式有基于session方式和基于token方式等
授权:
即认证通过后,也不是所有的资源都能访问。拥有资源的访问权限则正常访问,没有权限则拒绝访问
RBAC(Role-Based Access Control) 基于角色的访问控制
有很多权限,把权限一个一个加给用户很繁琐,所以 将一组权限打包给一个角色,再让用户和角色挂钩。说白了,一个角色就是一组权限。
一个用户可以拥有多个角色,一个角色可以被多个用户拥有。一个权限可以对应多个角色,一个角色可以对应多个权限。均为多对多,即RBAC底层最少需要5张表。
- xc_user:用户表,存储所有用户的基本信息,姓名、邮箱…
- xc_role:角色表,根据业务需求。角色的创建是为了方便给用户分配权限。(一个用户有多个角色,一个角色下也可以有多个用户,多对多,需要中间表,中间表存两个表的主键即可)
- xc_user_role:
用户角色表(中间表,用户和角色的关系表)
- xc_menu:权限表,记录了菜单及菜单下的权限。权限,是对资源的访问控制。一个角色可拥有多个权限,一个权限可被多个角色所拥有。(角色与权限多对多,需要中间表)
- xc_permission:
角色权限表(中间表,角色和权限的关系表)
3、Java安全框架的实现
- Shiro:轻量级的安全框架,提供认证、授权、会话管理、密码管理、缓存管理等功能
- Spring Security:功能比Shiro强大,更复杂,权限控制细粒度更高,对OAuth2 支持更好,与Spring 框架无缝集合,使Spring Boot 集成很快捷。
- 自己写:基于过滤器(filter)和AOP来实现,难度大,没必要
Spring Security是一个能够为基于Spring的企业应用系统提供
声明式(注解)
的安全访问控制解决方案的安全框架。
https://spring.io/projects/spring-security
4、入门案例
给需要保护的微服务添加spring-boot-starter-security依赖即可。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--版本在父工程中取-->
此时再访问上面controller中的接口,就会被Spring Security拦截,且Spring Security还提供了一个登录界面。
使用默认用户user登录,密码在控制台可找到,是一个随机生成的UUID字符串:
使用curl访问:
curl -v -X GET -u"user:550e8400-e29b-41d4-a716-446655440000" http://localhost:9527/admin/query
退出登录则访问:
loclhost:port/logout
以上只是个入门案例,当然密码和用户肯定不是这么存的。
4、使用配置文件配置用户名和密码
添加配置:
spring:
security:
user:
name: admin
password: admin123
重启服务,此时控制台上不再为我们生成密码,用上面自己配置的密码登录即可:
当然这个还是临时给自己调试用的,生产环境不这么搞。接下来 看下源码实现,在application.yml 中 将鼠标指定到name那,按住ctrl键,单击鼠标左键
5、基于内存的多用户管理
在config目录下创建配置类:
@Configuration
public class MySecurityUserConfig {
@Bean
public UserDetailsService userDetailService() {
//使用org.springframework.security.core.userdetails.User类来定义用户
//定义两个用户
UserDetails user1 = User.builder().username("liu").password("123456").roles("student").build();
UserDetails user2 = User.builder().username("Mr.liu").password("123456").roles("teacher").build();
//创建两个用户,信息存内存中
InMemoryUserDetailsManager userDetailsManager = new InMemoryUserDetailsManager();
userDetailsManager.createUser(user1);
userDetailsManager.createUser(user2);
return userDetailsManager;
}
}
重启服务,访问接口,跳登录页面后,输入上面定义的用户名和密码,控制台报错:
这个是因为spring Sercurity强制要使用密码加密,当然我们也可以不加密,但是官方要求是不管你是否加密,
都必须配置一个密码编码(加密)器
继续在MySecurityUserConfig类中定义bean:
/*
* 从 Spring5 开始,强制要求密码要加密
* 如果非不想加密,可以使用一个过期的 PasswordEncoder 的实例 NoOpPasswordEncoder,
* 但是不建议这么做,毕竟不安全。
*
* @return
*/
@Bean
public PasswordEncoder passwordEncoder(){
//不对密码进行加密,使用明文
return NoOpPasswordEncoder.getInstance();
}
重启后再登录上面定义的用户,则可以登录成功。且此时,yaml配置文件中的用户名和密码就失效了。此时,有以下几个问题: