Spring Security 用户认证

àì夳堔傛蜴生んèń 2022-11-18 01:28 339阅读 0赞

前言

描述: Spring Security 入门系列文章。
【1】Spring Security 用户认证
【2】Spring Security 用户授权

1 SpringSecurity 简介

在这里插入图片描述

1.1 框架简介

Spring 是非常流行和成功的 Java 应用开发框架,Spring Security 正是 Spring 家族中的成员。Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案。
正如你可能知道的关于安全方面的两个主要区域是“认证”和“授权”(或者访问控制),一般来说,Web 应用的安全性包括用户认证(Authentication)和用户授权(Authorization)两个部分,这两点也是 Spring Security 重要核心功能。
(1)用户认证指的是:验证某个用户是否为系统中的合法主体,也就是说用户能否访问该系统。用户认证一般要求用户提供用户名和密码。系统通过校验用户名和密码来完成认证过程。通俗点说就是系统认为用户是否能登录
(2)用户授权指的是验证某个用户是否有权限执行某个操作。在一个系统中,不同用户所具有的权限是不同的。比如对一个文件来说,有的用户只能进行读取,而有的用户可以进行修改。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。通俗点讲就是系统判断用户是否有权限去做某些事情。

1.2 Spring Security和Shiro比较

在 Java 生态中,目前有 Spring Security 和 Apache Shiro 两个安全框架,可以完成认证和授权的功能。

相同点

  1. 1:认证功能
  2. 2:授权功能
  3. 3:加密功能
  4. 4:会话管理
  5. 5:缓存支持
  6. 6rememberMe功能.......

不同点
优点:

  1. 1Spring Security基于Spring开发,项目中如果使用Spring作为基础,配合Spring Security做权限更加
  2. 方便,而Shiro需要和Spring进行整合开发
  3. 2Spring Security功能比Shiro更加丰富些,例如安全防护
  4. 3Spring Security社区资源比Shiro丰富

缺点:

  1. 1Shiro的配置和使用比较简单,Spring Security上手复杂
  2. 2Shiro依赖性低,不需要任何框架和容器,可以独立运行,而Spring Security依赖于Spring容器

一般来说,常见的安全管理技术栈的组合是这样的:

  1. SSM + Shiro
  2. Spring Boot/Spring Cloud +Spring Security

1.3 权限管理中的相关概念

1.3.1 主体

英文单词:principal
使用系统的用户或设备或从其他系统远程登录的用户等等。简单说就是谁使用系统谁就是主体。

1.3.2 认证

英文单词:authentication
权限管理系统确认一个主体的身份,允许主体进入系统。简单说就是“主体”证明自己是谁。笼统的认为就是以前所做的登录操作。

1.3.3 授权

英文单词:authorization
将操作系统的“权力”“授予”“主体”,这样主体就具备了操作系统中特定功能的能力。

2 简单用户认证

在这里插入图片描述

2.1 pom

  1. <parent>
  2. <groupId>org.springframework.boot</groupId>
  3. <artifactId>spring-boot-starter-parent</artifactId>
  4. <version>2.3.1.RELEASE</version>
  5. <relativePath/> <!-- lookup parent from repository -->
  6. </parent>
  7. <properties>
  8. <java.version>1.8</java.version>
  9. </properties>
  10. <dependencies>
  11. <dependency>
  12. <groupId>org.springframework.boot</groupId>
  13. <artifactId>spring-boot-starter-web</artifactId>
  14. </dependency>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-security</artifactId>
  18. </dependency>
  19. <!--测试-->
  20. <dependency>
  21. <groupId>org.springframework.boot</groupId>
  22. <artifactId>spring-boot-starter-test</artifactId>
  23. <scope>test</scope>
  24. </dependency>
  25. <dependency>
  26. <groupId>junit</groupId>
  27. <artifactId>junit</artifactId>
  28. </dependency>
  29. <!--公用依赖-->
  30. <dependency>
  31. <groupId>org.projectlombok</groupId>
  32. <artifactId>lombok</artifactId>
  33. </dependency>
  34. <dependency>
  35. <groupId>com.alibaba</groupId>
  36. <artifactId>fastjson</artifactId>
  37. <version>1.2.71</version>
  38. </dependency>
  39. <dependency>
  40. <groupId>org.apache.commons</groupId>
  41. <artifactId>commons-collections4</artifactId>
  42. <version>4.2</version>
  43. </dependency>
  44. <dependency>
  45. <groupId>org.apache.commons</groupId>
  46. <artifactId>commons-lang3</artifactId>
  47. </dependency>
  48. </dependencies>
  49. <build>
  50. <plugins>
  51. <plugin>
  52. <groupId>org.springframework.boot</groupId>
  53. <artifactId>spring-boot-maven-plugin</artifactId>
  54. </plugin>
  55. <plugin>
  56. <groupId>org.apache.maven.plugins</groupId>
  57. <artifactId>maven-compiler-plugin</artifactId>
  58. <version>3.6.1</version>
  59. <configuration>
  60. <source>1.8</source>
  61. <target>1.8</target>
  62. </configuration>
  63. </plugin>
  64. </plugins>
  65. </build>

2.2 application.yml

  1. server:
  2. port: 8888

2.3 SpringSecurity 用户自定义配置类

描述: 用户需要继承WebSecurityConfigurerAdapter来实现自定义配置。

  1. /** * @Description: Spring Security 自定义配置类 * @Author: rosh * @Date: 2021/4/10 11:16 */
  2. @Configuration
  3. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  4. @Autowired
  5. @Qualifier("roshUserDetailService")
  6. private RoshUserDetailService roshUserDetailService;
  7. /** * 配置登录用户名、密码及角色 */
  8. @Override
  9. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  10. auth.userDetailsService(roshUserDetailService).passwordEncoder(passwordEncoder());
  11. }
  12. /** * 配置加密方式,官方推荐加密方式为BCrypt */
  13. @Bean
  14. public PasswordEncoder passwordEncoder() {
  15. return new BCryptPasswordEncoder();
  16. }
  17. }

2.4 用户自定义认证方式

描述: 用户需要实现UserDetailsService 来实现自定义用户认证

  1. /** * @Description: 自定义认证类 * @Author: rosh * @Date: 2021/4/11 10:30 */
  2. @Service("roshUserDetailService")
  3. public class RoshUserDetailService implements UserDetailsService {
  4. /** * UserDetails:返回用户的主体 */
  5. @Override
  6. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  7. //配置一个admin、123456的用户
  8. List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
  9. return new User("admin", new BCryptPasswordEncoder().encode("123456"), auths);
  10. }
  11. }

2.5 相关业务类

  1. @AllArgsConstructor
  2. @NoArgsConstructor
  3. @Data
  4. public class Student {
  5. private Integer id;
  6. private String name;
  7. private String hobby;
  8. }
  9. @RestController
  10. @RequestMapping("/student")
  11. public class StudentController {
  12. @GetMapping("/{id}")
  13. public Student getStudent(@PathVariable("id") Integer id) {
  14. return new Student(id, "rosh", "basketBall");
  15. }
  16. }
  17. @SpringBootApplication
  18. public class RoshSerucityApplication {
  19. public static void main(String[] args) {
  20. SpringApplication.run(RoshSerucityApplication.class);
  21. }
  22. }

2.6 测试

访问接口:http://localhost:8888/student/1
在这里插入图片描述
描述: 输入admin、123456
在这里插入图片描述

3 数据库认证

3.1 数据库环境

  1. -- 创表语句
  2. CREATE TABLE `t_user` (
  3. `id` bigint(20) NOT NULL AUTO_INCREMENT,
  4. `username` varchar(20) NOT NULL,
  5. `password` varchar(100) DEFAULT NULL,
  6. PRIMARY KEY (`id`),
  7. UNIQUE KEY `username` (`username`)
  8. ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8;
  9. -- 插入管理员数据admin123456
  10. insert into t_user(username,password) VALUES('admin','$2a$10$YDq3287Iw86gFr3RyKl7fe7JYQCkoic5K0XOgoSDpJgQEdYkWvxKG')

在这里插入图片描述

3.2 更新pom文件

  1. <!--数据库-->
  2. <dependency>
  3. <groupId>com.baomidou</groupId>
  4. <artifactId>mybatis-plus-boot-starter</artifactId>
  5. <version>3.3.2</version>
  6. </dependency>
  7. <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
  8. <dependency>
  9. <groupId>mysql</groupId>
  10. <artifactId>mysql-connector-java</artifactId>
  11. <version>5.1.47</version>
  12. </dependency>

在这里插入图片描述

3.3 修改application.yml

  1. server:
  2. port: 8888
  3. spring:
  4. #数据库连接池
  5. datasource:
  6. url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=Asia/Shanghai
  7. username: root
  8. password: 123456
  9. driver-class-name: com.mysql.jdbc.Driver
  10. mybatis-plus:
  11. #默认值classpath*:/mapper/**/*.xml
  12. mapper-locations: classpath:/mapper/*.xml #配置全局自增ID global-config: db-config: id-type: auto

3.4 mybatis业务类

在这里插入图片描述

  1. @Data
  2. @TableName(value = "t_user")
  3. public class UserEntity {
  4. @TableId
  5. private Integer id;
  6. private String username;
  7. private String password;
  8. }
  9. @Mapper
  10. public interface UserMapper extends BaseMapper<UserEntity> {
  11. }
  12. @Service
  13. public class UserService extends ServiceImpl<UserMapper, UserEntity> {
  14. public UserEntity findUserByUsername(@NonNull final String username) {
  15. QueryWrapper<UserEntity> wrapper = new QueryWrapper<>();
  16. wrapper.eq("username", username);
  17. return baseMapper.selectOne(wrapper);
  18. }
  19. }

3.5 修改RoshSerucityApplication

  1. @SpringBootApplication
  2. @MapperScan("com.rosh.security.mapper")
  3. public class RoshSerucityApplication {
  4. public static void main(String[] args) {
  5. SpringApplication.run(RoshSerucityApplication.class);
  6. }
  7. }

3.6 修改用户自定义认证类

描述: 修改RoshUserDetailService

  1. @Service("roshUserDetailService")
  2. public class RoshUserDetailService implements UserDetailsService {
  3. @Autowired
  4. private UserService userService;
  5. /** * UserDetails:返回用户的主体 */
  6. @Override
  7. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  8. //1 查询db
  9. UserEntity user = userService.findUserByUsername(username);
  10. //2 不存在认证失败
  11. if (user == null) {
  12. throw new UsernameNotFoundException("用户名不存在");
  13. }
  14. //3 校验
  15. List<GrantedAuthority> auths = AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
  16. return new User(user.getUsername(), user.getPassword(), auths);
  17. }
  18. }

3.7 测试

  1. http://localhost:8888/student/1

描述: 错误登录
在这里插入图片描述

描述: 正确登录
在这里插入图片描述

4 自定义登录页面及访问控制

4.1 修改Spring Security 自定义配置类

描述: 重写configure方法。
在这里插入图片描述

  1. @Configuration
  2. public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
  3. @Autowired
  4. @Qualifier("roshUserDetailService")
  5. private RoshUserDetailService roshUserDetailService;
  6. /** * 配置登录用户名、密码及角色 */
  7. @Override
  8. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  9. auth.userDetailsService(roshUserDetailService).passwordEncoder(passwordEncoder());
  10. }
  11. /** * 配置加密方式,官方推荐加密方式为BCrypt */
  12. @Bean
  13. public PasswordEncoder passwordEncoder() {
  14. return new BCryptPasswordEncoder();
  15. }
  16. /** * 自定义页面配置、登录访问配置 */
  17. @Override
  18. protected void configure(HttpSecurity http) throws Exception {
  19. http.formLogin()
  20. //配置登录页面
  21. .loginPage("/login.html")
  22. //登录访问路径
  23. .loginProcessingUrl("/user/login").permitAll()
  24. //登录成功访问接口
  25. .defaultSuccessUrl("/user/login/success")
  26. //登录失败访问的接口
  27. .failureForwardUrl("/user/login/failed")
  28. //配置url访问权限,登录url可以直接访问,不需要认证
  29. .and().authorizeRequests().antMatchers("/login.html", "/user/login/failed").permitAll()
  30. //其余url需要认证才能访问
  31. .anyRequest().authenticated()
  32. //关闭csrf
  33. .and().csrf().disable();
  34. }
  35. }

4.2 登录页面

在这里插入图片描述
描述: 表单方法必须为post,name必须为username,password。查看核心过滤器,UsernamePasswordAuthenticationFilter。

在这里插入图片描述

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <title>登录页面</title>
  6. </head>
  7. <body>
  8. <form action="/user/login" method="post">
  9. 用户名:<input type="text" name="username">
  10. <br/>
  11. 密码: <input type="text" name="password">
  12. <br/>
  13. <input type="submit" value="登录">
  14. </form>
  15. </body>
  16. </html>

4.3 相关业务类

  1. @RestController
  2. @RequestMapping("/user")
  3. public class UserController {
  4. @GetMapping("/login/success")
  5. public String loginSuccess() {
  6. return "用户认证成功";
  7. }
  8. @PostMapping("/login/failed")
  9. public String loginFailed() {
  10. return "用户认证失败";
  11. }
  12. }

4.4 测试

描述: 直接访问student接口:http://localhost:8888/student/1会重定向到登录页面

在这里插入图片描述
在这里插入图片描述
描述: 登录失败测试。

在这里插入图片描述
在这里插入图片描述
描述: 登录成功测试
在这里插入图片描述
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,339人围观)

还没有评论,来说两句吧...

相关阅读