原创首发
SpringSecurity跟SpringBoot的整合-从数据库中读取用户信息校验

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可以多表联立查询
详情可以看一下大锯写的这篇文章
写好了查询用户的服务,那是不是要跟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();
}
再次运行登录
测试通过