5 SpringSecurity使用数据库数据完成认证

5.1 认证流程分析
5.1.1 UsernamePasswordAuthenticationFilter

还记得我们在前面将的15个过滤器吧,这个过滤器就是其中之一。
先看主要负责认证的过滤器UsernamePasswordAuthenticationFilter,看重点,注意注释。
我们首先Ctrl+N在对话框里面输入这个过滤器的名字。

在这里插入图片描述

我们点击最后一行代码的authenticate方法。看看具体的认证流程是什么样子的。

5.1.2 AuthenticationManager

我们进入这个方法之后,发现这个方法是一个接口提供的。

在这里插入图片描述

由上面源码得知,真正认证操作在AuthenticationManager里面!然后看AuthenticationManager的实现类ProviderManager:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

点击进入authenticate方法,进一步观察认证流程:

在这里插入图片描述

我们发现这个方法也是一个接口提供的方法。我们查看其实现类。

在这里插入图片描述

5.1.3 AbstractUserDetailsAuthenticationProvider

在这里插入图片描述

在DaoAuthenticationProvider这个类里面:

在这里插入图片描述

我们查看this.getUsrDetailService()方法。

在这里插入图片描述

这个方法的返回值是UserDetailService。点击UserDetailService查看源码:

在这里插入图片描述

5.1.4 AbstractUserDetailsAuthenticationProvider中authenticate返回值

按理说到此已经知道自定义认证方法的怎么写了,但咱们把返回的流程也大概走一遍,上面不是说到返回了一个UserDetails对象对象吗?跟着它,就又回到了AbstractUserDetailsAuthenticationProvider对象中authenticate方法的最后一行了。

在这里插入图片描述

点进去看看:
在这里插入图片描述

来到UsernamePasswordAuthenticationToken对象发现里面有两个构造方法。
注意:这里传递的是三个参数,开局传递的是两个参数。

在这里插入图片描述

我们看看这个类的父类做了什么?点击super

在这里插入图片描述

由此,咱们需要牢记自定义认证业务逻辑返回的UserDetails对象中一定要放置权限信息啊!可是这里面也没有doFilter呀?那就从父类找!

在这里插入图片描述

5.1.5 AbstractAuthenticationProcessingFilter

在这里插入图片描述

点击successfulAuthentication方法。

在这里插入图片描述

可见AbstractAuthenticationProcessingFilter这个过滤器对于认证成功与否,做了两个分支,成功执行successfulAuthentication,失败执行unsuccessfulAuthentication。在successfulAuthentication内部,将认证信息存储到了SecurityContext中。并调用了loginSuccess方法,这就是常见的“记住我”功能!此功能具体应用,咱们后续再研究!

5.2 初步实现认证功能
5.2.1 编写UserService接口

让我们自己的UserService接口继承UserDetailsService。

在这里插入图片描述

5.2.2 实现UserService接口

定义UserServiceImpl类,实现这个接口,编写loadUserByUsername业务。

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 根据用户名查询用户信息
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = userDao.findUserByName(username);
        List<Role> roles = userInfo.getRoles();
        User user = new User(userInfo.getUsername(),{noop}+userInfo.getPassword(),getAuthority(roles));
        System.out.println(user);
        return user;
    }
    //封装角色信息,也就是认证信息
    public Collection getAuthority(List<Role> roles){
        List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>();
        for(Role role : roles){
            String roleName = role.getRoleName();
            list.add(new SimpleGrantedAuthority("ROLE_" + roleName));
        }
        return list;
    }
}
5.2.3 在SpringSecurity主配置文件中指定认证使用的业务对象
<!--配置认证管理器-->
<security:authentication-manager>
    <security:authentication-provider user-service-ref="userService">
    </security:authentication-provider>
</security:authentication-manager>
5.3 加密认证
5.3.1 在IOC容器中提供加密对象

在springSecurity.xml里面配置加密对象。

<!--配置加密工具类-->
<bean id="bCryptPasswordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></bean>

配置加密认证方式

<!--配置认证管理器-->
<security:authentication-manager>
    <!--配置认证提供者-->
    <security:authentication-provider user-service-ref="userService">
               <!-- 配置加密的方式-->
        <security:password-encoder ref="bCryptPasswordEncoder"/>
    </security:authentication-provider>
</security:authentication-manager>
5.3.2 修改认证方法

去掉{noop}。

@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    UserDao userDao;

    @Autowired
    BCryptPasswordEncoder bCryptPasswordEncoder;

    /**
     * 根据用户名查询用户信息
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo userInfo = userDao.findUserByName(username);
        List<Role> roles = userInfo.getRoles();
        User user = new User(userInfo.getUsername(),userInfo.getPassword(),userInfo.getStatus() == 0 ? false : true, true, true, true,getAuthority(roles));
        System.out.println(user);
        return user;
    }
    //封装角色信息,也就是认证信息
    public Collection getAuthority(List<Role> roles){
        List<SimpleGrantedAuthority> list = new ArrayList<SimpleGrantedAuthority>();
        for(Role role : roles){
            String roleName = role.getRoleName();
            list.add(new SimpleGrantedAuthority("ROLE_" + roleName));
        }
        return list;
    }
5.3.3 修改添加用户的操作
//新增用户信息
public void save(UserInfo userInfo) {
    //加密之后的密码信息
    String encode = bCryptPasswordEncoder.encode(userInfo.getPassword());
    userInfo.setPassword(encode);
    userDao.save(userInfo);
}执行新增操作:

在这里插入图片描述

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐