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

前面运行写好的代码之所以没有任何显示,是因为还没有对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. Linux_tail总结

    tail 命令用法 功能从尾部显示文件若干行 语法: tail [ +/- num ][参数] 文件名 使用tail命令的-f选项可以方便的查阅正在改变的日志文件,tail -f filename会把 ...

  2. js中new的原理

    面向对象 在了解new的原理之前,先简单地了解一下构造函数和对象. js可以通过构造函数创建对象: function Test() { } var t = new Test(); 构造函数的首字母大写 ...

  3. 【debug技巧】jstat:虚拟机统计信息监视器

    我们在日常开发时,难免会遇到一些没有内存泄漏等问题.有时,我们无法下载arthas等开源的诊断工具.这时候,我们就可以借助JDK自带的一些诊断工具. 首先我们可以使用jstat查看gc信息 字段含义 ...

  4. 认识RocketMQ4.x架构设计

    消息模型 单体的消息模型 RocketMQ消息模型跟其他的消息队列一样 都是 producer - > topic->consumer producer 生产消息 也就是发送者 topic ...

  5. Deployment必须包含资源对象

    Deployment 是一个控制器,能够用来控制 pod 数量跟期望数量一致,配置 pod 的发布方式 Deployment 会按照给定策略进行发布指定 pod,保证在更新过程中不可用数量在限定范围内 ...

  6. 修复 Elasticsearch 集群的常见错误和问题

    文章转载自:https://mp.weixin.qq.com/s/8nWV5b8bJyTLqSv62JdcAw 第一篇:Elasticsearch 磁盘使用率超过警戒水位线 从磁盘常见错误说下去 当客 ...

  7. Elasticsearch:ICU分词器介绍

    ICU Analysis插件是一组将Lucene ICU模块集成到Elasticsearch中的库. 本质上,ICU的目的是增加对Unicode和全球化的支持,以提供对亚洲语言更好的文本分割分析. 从 ...

  8. kubernetes为容器定义环境变量

    示例Pod 的配置文件 envars.yaml Copy envars.yaml to clipboard apiVersion: v1 kind: Pod metadata: name: envar ...

  9. 关联Prometheus与Alertmanager

    在Prometheus的架构中被划分成两个独立的部分.Prometheus负责产生告警,而Alertmanager负责告警产生后的后续处理.因此Alertmanager部署完成后,需要在Prometh ...

  10. Maven快速配置和入门

    概念 Maven其实就是一个管理项目.构建项目的工具.它有标准化的项目结构.构建流程.依赖管理. 功能 Maven提供了一套标准的项目结构 Maven提供了一套标准的构建流程 Maven提供了更便捷的 ...