您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~

前面运行写好的代码之所以没有任何显示,是因为还没有对Spring Security进行配置,当然啥也不显示了。这就好比你坐在车上,却不打开发动机,车子当然跑不起来。所以咱们就来让它跑起来。不过在配置之前,有必要对Spring Security的登录流程做个大致了解。

如果深入源码去了解,这个玩意及其复杂,但是没必要,知道它的机制就行了。就好比你买车也不必把发动机拆开去看它是怎么工作的吧。简单来说它就是下面这些步骤:

1、Spring Security通过AuthenticationManager接口进行身份验证

2、ProviderManager是AuthenticationManager的一个默认实现

3、ProviderManager把验证工作委托给了AuthenticationProvider接口

4、AuthenticationProvider的实现类DaoAuthenticationProvider会检查身份认证

5、DaoAuthenticationProvider又把认证工作委托给了UserDetailsService接口

6、自定义UserDetailsService类从数据库中获取用户账号、密码、角色等信息,然后封装成UserDetails返回

7、使用Spring Security还需要自定义AuthenticationProvider接口,获取用户输入的账号、密码等信息,并封装成Authentication接口

8、将UserDetails和Authentication进行比对,如果一致就返回UsernamePasswordAuthenticationToken,否则抛出异常

下面是认证流程图:

首先重写loadUserByUsername:

  1. /**
  2. * 自定义用户详情
  3. *
  4. * @author 湘王
  5. */
  6. @Service("userDetailsService")
  7. public class CustomUserDetailsService implements UserDetailsService {
  8. @Autowired
  9. private UserService userService;
  10. @Autowired
  11. private RoleService roleService;
  12. @Autowired
  13. private UserRoleService userRoleService;
  14.  
  15. @Override
  16. public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  17. Collection<GrantedAuthority> authorities = new ArrayList<>();
  18. // 从数据库中取出用户信息
  19. SysUser user = userService.getByName(username);
  20. // 判断用户是否存在
  21. if(null == user) {
  22. System.out.println("user is not exist");
  23. throw new UsernameNotFoundException("user is not exist");
  24. }
  25.  
  26. // 获得用户角色:方式一
  27. List<SysUserRole> list = userRoleService.getByUserId(user.getId());
  28. // // 获得用户角色:方式二
  29. // List<SysRole> list = roleService.getByUserId(user.getId());
  30.  
  31. // // 给用户添加授权:方式一
  32. // for (SysUserRole userRole : list) {
  33. // SysRole role = roleService.getById(userRole.getRoleid());
  34. // authorities.add(new SimpleGrantedAuthority(role.getName()));
  35. // }
  36. // // 返回UserDetails实现类
  37. // return new User(user.getName(), user.getPassword(), authorities);
  38.  
  39. // 给用户添加授权:方式二
  40. return User
  41. .withUsername(username)
  42. .password(user.getPassword())
  43. .authorities(list.stream()
  44. .filter(Objects::nonNull)// 判断是否为空
  45. .map(userRole -> roleService.getById(userRole.getRoleid()))// 从SysUserRole获取Role
  46. .map(SysRole::getName)// 转变为角色名称字符串
  47. .map(SimpleGrantedAuthority::new)// 依据角色名称创建SimpleGrantedAuthority
  48. .toArray(SimpleGrantedAuthority[]::new)// list转变为数组
  49. ).build();
  50. }
  51. }

因为UserDetailsService返回了封装的UserDetails,所以需要再自定义AuthenticationProvider返回Authentication接口:

  1. /**
  2. * 自定义登录验证
  3. *
  4. * @author 湘王
  5. */
  6. @Component
  7. public class CustomAuthenticationProvider implements AuthenticationProvider {
  8. @Autowired
  9. private CustomUserDetailsService customUserDetailsService;
  10.  
  11. @Override
  12. public Authentication authenticate(Authentication authentication) throws AuthenticationException {
  13. // 获取表单输入中返回的用户名
  14. String username = (String) authentication.getPrincipal();
  15. // 获取表单中输入的密码
  16. String password = (String) authentication.getCredentials();
  17. // 这里调用我们的自己写的获取用户的方法
  18. UserDetails userInfo = customUserDetailsService.loadUserByUsername(username);
  19. if (userInfo == null) {
  20. System.out.println("user is not exist");
  21. throw new UsernameNotFoundException("user is not exist");
  22. }
  23.  
  24. PasswordEncoder passwordEncoder = new PasswordEncoder() {
  25. @Override
  26. public String encode(CharSequence charSequence) {
  27. return charSequence.toString();
  28. }
  29. @Override
  30. public boolean matches(CharSequence charSequence, String s) {
  31. return s.equals(charSequence.toString());
  32. }
  33. };
  34.  
  35. // 采用简单密码验证
  36. if (!passwordEncoder.matches(password, userInfo.getPassword())) {
  37. System.out.println("user or password error");
  38. throw new BadCredentialsException("user or password error");
  39. }
  40.  
  41. Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
  42. // 构建返回的用户登录成功的token
  43. return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
  44. }
  45.  
  46. @Override
  47. public boolean supports(Class<?> aClass) {
  48. return true;
  49. }
  50. }

接着来实现实现WebSecurityConfigurerAdapter,它通过重写WebSecurityConfigurerAdapter中的相关方法(一般是configurer)来自定义配置。WebSecurityConfigurerAdapter主要做几件事:

1、初始化

2、开启Security

3、配置各种过滤器,实现验证过滤器链

下面是它的代码:

  1. /**
  2. * spring security验证配置
  3. *
  4. * @author 湘王
  5. */
  6. // 配置类
  7. @Configuration
  8. // 开启Security服务
  9. @EnableWebSecurity
  10. // 开启全局Securtiy注解
  11. @EnableGlobalMethodSecurity(prePostEnabled = true)
  12. public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
  13. @Autowired
  14. private CustomUserDetailsService customUserDetailsService;
  15. @Autowired
  16. private CustomAuthenticationProvider authenticationProvider;
  17.  
  18. // 自定义的登录验证逻辑
  19. @Override
  20. protected void configure(AuthenticationManagerBuilder auth) throws Exception {
  21. auth.authenticationProvider(authenticationProvider);
  22. }
  23. // 控制逻辑
  24. @Override
  25. protected void configure(HttpSecurity http) throws Exception {
  26. // 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
  27. http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class);
  28.  
  29. http.authorizeRequests()
  30. .anyRequest().authenticated()
  31. // 设置自定义认证成功、失败及登出处理器
  32. .and().formLogin().loginPage("/login")
  33. .and().cors()
  34. .and().csrf().disable();
  35. }
  36. @Override
  37. public void configure(WebSecurity web) throws Exception {
  38. // 设置拦截忽略文件夹,可以对静态资源放行
  39. web.ignoring().antMatchers("/css/**", "/js/**");
  40. }
  41. }

接着用postman进行测试:

回顾整个调用过程,它的时序图是:

但是等等:好像除了/login,其他方法都不能正常访问!


感谢您的大驾光临!咨询技术、产品、运营和管理相关问题,请关注后留言。欢迎骚扰,不胜荣幸~

Spring Security(3)的更多相关文章

  1. Spring Security(08)——intercept-url配置

    http://elim.iteye.com/blog/2161056 Spring Security(08)--intercept-url配置 博客分类: spring Security Spring ...

  2. Spring Security(三)

    Spring Security(三) 个性化用户认证流程 自定义登录页面 在配置类中指定登录页面和接收登录的 url @Configuration public class BrowserSecuri ...

  3. Spring Security(二)

    Spring Security(二) 注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看.:-) 定义用户认证逻辑 用户登录成功后,用户的信息会被 Security 封装在 ...

  4. Spring Security(一)

    Spring Security(一) 基本原理 前言 Spring Security核心功能 认证(你是谁) 授权(你能干什么) 攻击防护(防止伪造身份) Srping Security基本原理 项目 ...

  5. 【权限管理系统】Spring security(三)---认证过程(原理解析,demo)

      在前面两节Spring security (一)架构框架-Component.Service.Filter分析和Spring Security(二)--WebSecurityConfigurer配 ...

  6. SpringBoot集成Spring Security(7)——认证流程

    文章目录 一.认证流程 二.多个请求共享认证信息 三.获取用户认证信息 在前面的六章中,介绍了 Spring Security 的基础使用,在继续深入向下的学习前,有必要理解清楚 Spring Sec ...

  7. SpringBoot集成Spring Security(6)——登录管理

    文章目录 一.自定义认证成功.失败处理 1.1 CustomAuthenticationSuccessHandler 1.2 CustomAuthenticationFailureHandler 1. ...

  8. SpringBoot集成Spring Security(5)——权限控制

    在第一篇中,我们说过,用户<–>角色<–>权限三层中,暂时不考虑权限,在这一篇,是时候把它完成了. 为了方便演示,这里的权限只是对角色赋予权限,也就是说同一个角色的用户,权限是 ...

  9. SpringBoot集成Spring Security(4)——自定义表单登录

    通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...

  10. SpringBoot集成Spring Security(2)——自动登录

    在上一章:SpringBoot集成Spring Security(1)——入门程序中,我们实现了入门程序,本篇为该程序加上自动登录的功能. 文章目录 一.修改login.html二.两种实现方式 2. ...

随机推荐

  1. e1000e网卡驱动在麒麟3.2.5上编译安装

    一.清空原驱动 因为系统安装完毕后系统中自带了e1000e的网卡驱动,会影响后面自行编译的驱动 所以先用find命令找出并删除掉所有关于e1000e的驱动文件 find / -name "* ...

  2. File类、FileOutputStream

    day01 File类 File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径) 使用File可以做到: 1:访问其表示的文件或目录的属性信息,例如:名字,大小, ...

  3. IO_对象流

    对象流 对象的本质是用来组织和存储数据的,对象本身也是数据.那么,能不能将对象存储到硬盘上的文件中呢?能不能将对象通过网络传输到另一个电脑呢?我们可以通过序列化和反序列化实现. java对象的序列化和 ...

  4. 新增一个Redis 从节点为什么与主节点的key数量不一样呢?

    在日常的 Redis 运维过程中,经常会发生重载 RDB 文件操作,主要情形有: 主从架构如果主库宕机做高可用切换,原从库会挂载新主库重新获取数据 主库 QPS 超过10万,需要做读写分离,重新添加从 ...

  5. http服务(postman调用方法及反参)

    #region 监听url #region 监听url路径请求 static HttpListener httpobj; private void listeningUrl() { //提供一个简单的 ...

  6. 《Java基础——线程类》

    Java基础--线程类       一.线程的创建之Thread类: 规则: 通过声明一个新类作为子类继承 Thread 类,并复写 run() 方法,就可以启动新线程并执行自己定义的 run()方法 ...

  7. Java SE 19 新增特性

    Java SE 19 新增特性 作者:Grey 原文地址: 博客园:Java SE 19 新增特性 CSDN:Java SE 19 新增特性 源码 源仓库: Github:java_new_featu ...

  8. 使用NextCloud搭建私有网络云盘并支持Office文档在线预览编辑以及文件同步

    转载自:https://www.bilibili.com/read/cv16835328?spm_id_from=333.999.0.0 0x00 前言简述 描述:由于个人家里的NAS以及公司团队对私 ...

  9. 路径参数和数值校验: Path_Parameters_and_Numeric_Validations

    官方文档地址: https://fastapi.tiangolo.com/zh/tutorial/path-params-numeric-validations/ # -*- coding: UTF- ...

  10. 使用nginx代理nexus,不是/根路径

    location /nexus/ { proxy_pass http://192.168.0.218:8081/; proxy_set_header Host $host:$server_port; ...