Spring Security(3)
  3EPyMqobg2PT 2023年11月01日 62 0

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

 

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

/** * 自定义用户详情 * * @author 湘王 */ @Service("userDetailsService") public class CustomUserDetailsService implements UserDetailsService { @Autowired private UserService userService; @Autowired private RoleService roleService; @Autowired private UserRoleService userRoleService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { Collection<GrantedAuthority> authorities = new ArrayList<>(); // 从数据库中取出用户信息
        SysUser user = userService.getByName(username); // 判断用户是否存在
        if(null == user) { System.out.println("user is not exist"); throw new UsernameNotFoundException("user is not exist"); } // 获得用户角色:方式一
        List<SysUserRole> list = userRoleService.getByUserId(user.getId()); //        // 获得用户角色:方式二 // List<SysRole> list = roleService.getByUserId(user.getId()); //        // 给用户添加授权:方式一 // for (SysUserRole userRole : list) { // SysRole role = roleService.getById(userRole.getRoleid()); // authorities.add(new SimpleGrantedAuthority(role.getName())); // } //        // 返回UserDetails实现类 // return new User(user.getName(), user.getPassword(), authorities); // 给用户添加授权:方式二
        return User .withUsername(username) .password(user.getPassword()) .authorities(list.stream() .filter(Objects::nonNull)// 判断是否为空
                                    .map(userRole -> roleService.getById(userRole.getRoleid()))// 从SysUserRole获取Role
                                    .map(SysRole::getName)// 转变为角色名称字符串
                                    .map(SimpleGrantedAuthority::new)// 依据角色名称创建SimpleGrantedAuthority
                                    .toArray(SimpleGrantedAuthority[]::new)// list转变为数组
 ).build(); } }

 

 

 

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

/** * 自定义登录验证 * * @author 湘王 */ @Component public class CustomAuthenticationProvider implements AuthenticationProvider { @Autowired private CustomUserDetailsService customUserDetailsService; @Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // 获取表单输入中返回的用户名
        String username = (String) authentication.getPrincipal(); // 获取表单中输入的密码
        String password = (String) authentication.getCredentials(); // 这里调用我们的自己写的获取用户的方法
        UserDetails userInfo = customUserDetailsService.loadUserByUsername(username); if (userInfo == null) { System.out.println("user is not exist"); throw new UsernameNotFoundException("user is not exist"); } PasswordEncoder passwordEncoder = new PasswordEncoder() { @Override public String encode(CharSequence charSequence) { return charSequence.toString(); } @Override public boolean matches(CharSequence charSequence, String s) { return s.equals(charSequence.toString()); } }; // 采用简单密码验证
        if (!passwordEncoder.matches(password, userInfo.getPassword())) { System.out.println("user or password error"); throw new BadCredentialsException("user or password error"); } Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities(); // 构建返回的用户登录成功的token
        return new UsernamePasswordAuthenticationToken(userInfo, password, authorities); } @Override public boolean supports(Class<?> aClass) { return true; } }

 

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

1、初始化

2、开启Security

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

 

下面是它的代码:

/** * spring security验证配置 * * @author 湘王 */
// 配置类
@Configuration // 开启Security服务
@EnableWebSecurity // 开启全局Securtiy注解
@EnableGlobalMethodSecurity(prePostEnabled = true) public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter { @Autowired private CustomUserDetailsService customUserDetailsService; @Autowired private CustomAuthenticationProvider authenticationProvider; // 自定义的登录验证逻辑
 @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider); } // 控制逻辑
 @Override protected void configure(HttpSecurity http) throws Exception { // 执行UsernamePasswordAuthenticationFilter之前添加拦截过滤
        http.addFilterBefore(new CustomInterceptorFilter(), UsernamePasswordAuthenticationFilter.class); http.authorizeRequests() .anyRequest().authenticated() // 设置自定义认证成功、失败及登出处理器
            .and().formLogin().loginPage("/login") .and().cors() .and().csrf().disable(); } @Override public void configure(WebSecurity web) throws Exception { // 设置拦截忽略文件夹,可以对静态资源放行
        web.ignoring().antMatchers("/css/**", "/js/**"); } }

 

 

接着用postman进行测试:

 

 

 

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

 

 

 

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

 

 


 

 

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

 

【版权声明】本文内容来自摩杜云社区用户原创、第三方投稿、转载,内容版权归原作者所有。本网站的目的在于传递更多信息,不拥有版权,亦不承担相应法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@moduyun.com

  1. 分享:
最后一次编辑于 2023年11月08日 0

暂无评论

推荐阅读
  2Vtxr3XfwhHq   2024年05月17日   55   0   0 Java
  Tnh5bgG19sRf   2024年05月20日   110   0   0 Java
  8s1LUHPryisj   2024年05月17日   46   0   0 Java
  aRSRdgycpgWt   2024年05月17日   47   0   0 Java
3EPyMqobg2PT