任何应用考虑到安全,绝不能明文的方式保存密码。密码应该通过哈希算法进行加密。有很多标准的算法比如SHA或者MD5,结合salt(盐)是一个不错的选择。 Spring Security提供了BCryptPasswordEncoder类,实现Spring的PasswordEncoder接口使用BCrypt强哈希方法来加密密码。
BCrypt强哈希方法 每次加密的结果都不一样。
(1)tensquare_user工程的pom引入依赖
<dependency>
<groupId>org.springframework.bootgroupId>
<artifactId>spring-boot-starter-securityartifactId>
dependency>
(2)添加配置类 (资源/工具类中提供)
我们在添加了spring security依赖后,所有的地址都被spring security所控制了,我们目前只是需要用到BCrypt密码加密的部分,所以我们要添加一个配置类,配置为所有地址都可以匿名访问。
package com.tensquare.user.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
/**
* 安全配置类
* 继承 WebSecurityConfigurerAdapter ,并重写它的方法来设置一些web安全的细节
*/
@Configuration
//注解开启Spring Security的功能
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
//通过 authorizeRequests() 定义哪些URL需要被保护、哪些不需要被保护。
.antMatchers("/**").permitAll()
.anyRequest().authenticated()
.and().csrf().disable();
}
/**
* BCryptPasswordEncoder加密工具类
* @return
*/
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
3)修改tensquare_user工程的Application, 配置bean(略)
/**
* BCryptPasswordEncoder加密工具类
* @return
*/
@Bean
public BCryptPasswordEncoder bcryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
1)修改tensquare_user工程的AdminService
@Autowired
private BCryptPasswordEncoder passwordEncoder;
/**
* 增加
* @param admin
*/
public void saveAdmin(Admin admin) {
admin.setId( idWorker.nextId()+"" );
//密码加密
admin.setPassword(passwordEncoder.encode(admin.getPassword()));
adminRepository.save(admin);
}
2)测试
POST http://localhost:9008/admin
{
"loginname": "admin",
"password": "123456",
"state": "1"
}
{
"loginname": "root",
"password": "123456",
"state": "1"
}
【提醒】同样的密码两次加密后的结果不一致。
(1)AdminRepository增加方法定义
/**
* 根据登录名查询返回管理员对象
* @param loginname
* @return
*/
Admin findByLoginname(String loginname);
(2)AdminService增加方法
/**
* 根据登录名和密码来查询管理员对象
* @param loginname
* @param password
* @return
*/
public Admin findAdminByLoginnameAndPassword(String loginname,String password){
//调用dao,根据用户名查询用户
Admin admin = adminRepository.findByLoginname(loginname);
//判断用户是否为空
if(null == admin){
//用户名不存在,则返回空
return null;
}
//用户存在,判断密码是否一致
if(passwordEncoder.matches(password,admin.getPassword())){
//返回管理员对象
return admin;
}else{
//密码不一致,也可以返回个性化的数据对象,或者抛异常
return null;
}
}
(3)AdminController增加方法
/**
* 管理员登录
* @param loginMap
* @return
*/
@PostMapping("/login")
public ResultDTO login(@RequestBody Map<String,String> loginMap){
//调用业务层查询
Admin admin =adminService.findAdminByLoginnameAndPassword(loginMap.get("loginname"),loginMap.get("password"));
//判断
if(null!=admin){
//登录成功
return new ResultDTO(true,StatusCode.OK,"登录成功");
}else{
//登录失败
return new ResultDTO(false,StatusCode.LOGINERROR,"用户名或密码错误");
}
}
(4)测试
POST http://localhost:9008/admin/login
{
"loginname": "admin",
"password": "1234561"
}
需求:用户按照手机号码来注册
(1)修改tensquare_user工程的UserService 类,引入BCryptPasswordEncoder,修改add方法,添加密码加密的逻辑。(注意不要修改错方法)
@Autowired
private BCryptPasswordEncoder passwordEncoder;
/**
* 增加,需要验证码校验
* @param user
* @param checkcode
*/
public void saveUser(User user,String checkcode) {
//1. 判断验证码是否正确
......
//密码加密
user.setPassword(passwordEncoder.encode(user.getPassword()));
userRepository.save(user);
......
//注册成功后,移除验证码
}
(2)测试运行后,添加数据
暂时注释掉验证码校验的代码,进行增加新用户测试:
POST http://localhost:9008/user
{
"mobile": "18516566522",
"password": "123456",
"nickname":"李老师"
}
(1)修改tensquare_user工程的UserRepository接口,增加方法定义
/**
* 根据手机号查询用户
* @param mobile
* @return
*/
User findByMobile(String mobile);
(2)修改tensquare_user工程的UserService 类,增加方法
/**
* 根据手机号和密码查询用户
* @param mobile
* @param password
* @return
*/
public User findUserByMobileAndPassword(String mobile,String password){
//调用dao,根据用户名查询用户
User user = userRepository.findByMobile(mobile);
//判断用户是否为空
if(null == user){
//用户名不存在,则返回空
return null;
}
//用户存在,判断密码是否一致
if(passwordEncoder.matches(password,user.getPassword())){
//返回用户对象
return user;
}else{
//密码不一致,也可以返回个性化的数据对象,或者抛异常
return null;
}
}
(3)修改tensquare_user工程的UserController类,增加login方法
/**
* 用户登录
* @param loginMap
* @return
*/
@PostMapping("/login")
public ResultDTO login(@RequestBody Map<String,String> loginMap){
//调用业务层查询
User user=userService.findUserByMobileAndPassword(loginMap.get("mobile"),loginMap.get("password"));
//判断
if(null!=user){
//登录成功
return new ResultDTO(true,StatusCode.OK,"登录成功");
}else{
//登录失败
return new ResultDTO(false,StatusCode.LOGINERROR,"用户名或密码错误");
}
}
(4)使用刚才新增加的账号进行测试,查看返回结果
POST http://localhost:9008/user/login
{
"mobile": "18516566522",
"password": "1234516"
}