1.项目的POJO类一定要实现序列化接口,否则获取到对象后无法使用其的get / set方法获取和设置其属性
例子:在做登陆页面时候,安全控制用的是弹簧安全,密码加密算法是BCrypt算法由于之前重新搭建项目,忘记
将实体类实现序列化接口,从而导致后台获取到实体类对象实例后,无法使用getPassword来来来来方法获取数据库中的密码,
导致前端发送给后台的数据无法与后台数据进行正确比对,导致无法登录进入系统。
如何发现的:因为其在登录页面进行密码校验时,导致系统一直进不去,因控制台一直不报错一直找不到错
误所在,遂尝试不使用BCrypt算法加密,使用固定用户名登录,登录进入系统后,获取用户资料时候报了实体类未序列化
错误,遂找到了之前使用BCrypt算法一直无法进入系统的原因
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd">
<!--页面拦截规则-->
<http pattern="/login.html" security="none" ></http>
<http pattern="/css/**" security="none"></http>
<http pattern="/js/**" security="none"></http>
<http pattern="/img/**" security="none"></http>
<http pattern="/plugins/**" security="none"></http>
<http use-expressions="false"> <!-- 是否实用spel表达式 -->
<intercept-url pattern="/**" access="ROLE_TEACHER"/>
<!-- 开启表单的登录功能 -->
<form-login login-page="/login.html" default-target-url="/admin/index.html" authentication-failure-url="/login.html" always-use-default-target="true"/> <!-- 表单自动生成的页面 -->
<!-- 以下页面不再拦截 -->
<csrf disabled="true"/>
<headers>
<frame-options policy="SAMEORIGIN" />
</headers>
<logout/>
</http>
<!-- 认证管理器 -->
<!-- <authentication-manager>
<authentication-provider>
<user-service>
<user name="20181201" password="123456" authorities="ROLE_TEACHER"/>
<user name="sunwukong" password="dasheng" authorities="ROLE_ADMIN"/>
</user-service>
</authentication-provider>
</authentication-manager> -->
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder ref="bcryptEncoder"></password-encoder>
</authentication-provider>
</authentication-manager>
<!-- 引用dubbo服务 -->
<dubbo:application name="usrms-teacher-web" />
<dubbo:registry address="zookeeper://192.168.25.128:2181"/>
<!-- 用id标识后 可以被其他bean对象引用,name标识后不可被其他对象引用 -->
<dubbo:reference id="teacherService" interface="com.usrms.teacher.service.TeacherService" ></dubbo:reference>
<!-- 相当于一个bean ,效果等同于注解支持 因为dubbox框架注解支持没有写此类所以bean的方式添加 -->
<beans:bean id="userDetailsService" class="com.usrms.service.UserDetailsServiceImpl">
<beans:property name="teacherService" ref="teacherService"></beans:property>
</beans:bean>
<beans:bean id="bcryptEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder"></beans:bean>
</beans:beans>
2. BCrypt加密算法通过密码校验实现修改密码功能
例子:因为项目要做修改密码的功能,所以需要知道BCrypt算法。中如何校验因为BCrypt算法。用的是哈希+盐的方式,过程不可逆,无法对其进行解密但是通过对BCryptPasswordEncoder类的查看发现其有自带的密码校验方法
BCryptPasswordEncoder.matches()源码:
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (encodedPassword == null || encodedPassword.length() == 0) {
logger.warn("Empty encoded password");
return false;
}
if (!BCRYPT_PATTERN.matcher(encodedPassword).matches()) {
logger.warn("Encoded password does not look like BCrypt");
return false;
}
return BCrypt.checkpw(rawPassword.toString(), encodedPassword);
}
通过观察分析源码,则发现可以直接调用BCryptPasswordEncoder.matches()方法将从数据库中获取到的加密的密码与前台传入的密码进行校验,方法会自动将前台传入的未加密密码与数据库中加密过的算法进行比对,故解决了修改密码的需求
项目中修改用户密码代码:
/**
* 修改用户密码
* @param oldPassword 原密码
* @param newPassword 新密码
* @return
*/
@RequestMapping("/alterPassword")
public Result alterPassword(String oldPassword,String newPassword) {
String username=SecurityContextHolder.getContext().getAuthentication().getName();
TbTeacher teacher=teacherService.findOne(username);
if(oldPassword==null||oldPassword.trim().length()==0) {
return new Result(false,"原密码输入不能为空");
}
if(newPassword==null||newPassword.trim().length()==0) {
return new Result(false,"新密码输入不能为空");
}
BCryptPasswordEncoder passwordEncoder=new BCryptPasswordEncoder();
try {
if(passwordEncoder.matches(oldPassword,teacher.getPassword())) {
teacher.setPassword(passwordEncoder.encode(newPassword));
teacherService.update(teacher);
return new Result(true,"密码修改成功,请重新登录");
}else {
return new Result(false,"原密码输入不正确");
}
}catch(Exception e) {
e.printStackTrace();
return new Result(false,"密码修改失败");
}
}