阳光沙滩
让学习编程变得简单
SpringSecurity跟SpringBoot的整合-从数据库中读取用户信息校验
发表于 2020-03-21    阅读次数 155

SpringSecurity跟SpringBoot的整合

从数据库中读取用户信息校验

前面文章:

SpringSecurity跟SpringBoot的整合-项目创建

SpringSecurity跟SpringBoot的整合-自定义登录页面

在前面的文章,我们已经配置好了自定义的登录页面

登录成功跳转,失败跳转

但是呢,以硬编码的形式返回用户名和密码

接下来我们就去数据库中获取用户的账号信息

实现UserDetailsService

package net.sunofbeach.security.service;

import net.sunofbeach.security.dao.UserDao;
import net.sunofbeach.security.domain.Role;
import net.sunofbeach.security.domain.SobUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Set;

@Service
@Transactional
public class UserService implements UserDetailsService {

    @Autowired
    private UserDao userDao;

    @Override
    public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException {
        //根据账号查询用户是否存在
        SobUser sobUser = userDao.findOneByUserName(userName);
        //如果不存在,直接返回null,表示认证失败
        if (sobUser == null) {
            return null;
        }
        try {
            //校验密码
            //第一种创建方式,看构造方法吧
            Collection<SimpleGrantedAuthority> authorties = new ArrayList<>();
            Set<Role> roles = sobUser.getRoles();
            for (Role role : roles) {
                SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role.getRoleName());
                authorties.add(simpleGrantedAuthority);
            }
            UserDetails userDetails = new User(sobUser.getUserName(), sobUser.getPassword(), authorties);
            return userDetails;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

这里的DAO可以多表联立查询

详情可以看一下大锯写的这篇文章

spring data jpa 多表操作之多对多

写好了查询用户的服务,那是不是要跟SpringSecurity关联起来呢?

怎么关联呢?

配置UserDetailsService

注释掉前面的硬编码用户


//    @Override
//    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//        //添加一个注册会员用户
//        auth.inMemoryAuthentication()
//                .passwordEncoder(new MyPasswordEncoder())
//                .withUser("test")
//                .password("123456")
//                .authorities("register");
//
//        //添加一个管理员帐户
//        auth.inMemoryAuthentication().passwordEncoder(new MyPasswordEncoder())
//                .withUser("admin")
//                .password("admin")
//                .authorities("register", "admin");
//    }

添加配置项

    @Override
    protected UserDetailsService userDetailsService() {
        return userService;
    }

添加密码Encoder

这个是被我们覆写过的,所以不需要加密和解密,是明文来的。

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new MyPasswordEncoder();
    }

登录

这是用户表里的数据

图片描述

登录一下吧

图片描述

密码加密

我们总不能把密码明文放在数据库里吧,你以为是CSDN吗?

如果你明文放在了数据库里,那数据库管理员不就可以看到了吗?对吧!

所以我们要进行加密

加密的话,我们直接返回BCryptPasswordEncoder即可

我们通过encode来加密密码,通过match来判断是否匹配

我们可以写一个测试程序,获得123456的加密内容,然后替换一下数据库里的内容

这样子就可以了。后面我们添加用户的逻辑,对明文进行加密以后再放到数据库里。

@RunWith(SpringRunner.class)
@SpringBootTest(classes = App.class)
public class TestPasswordEncode {


    @Test
    public void testPasswordEncode() {
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encode1 = encoder.encode("123456");
        System.out.println("result 1 -=-- > " + encode1);
        String encode2 = encoder.encode("123456");
        System.out.println("result 2 -- > " + encode2);
    }

}

输出结果

result 1 -=-- > $2a$10$eraZFqRgQb8a5bIkuFk6gupV1Lpv1ZLWpYYD1viJw9BEJQBVSK7nq
result 2 -- > $2a$10$25UuYacOGhobcHn2SgR1ceF66SjmLScFWaiTHCXLGI3noGVvLJXo.

两次输出结果不一样

这是动态盐加密

再去执行又会变了,加密出来的结果又是不一样的。

我们使用期中一个去替换数据库中的数据即可

图片描述

然后我们的encoder返回BCryptPasswordEncoder

    @Bean
    public PasswordEncoder getPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

再次运行登录

测试通过

图片描述