Spring Security - Password Encoder
Add Password Encoder
security.xml
<authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select email as username,passwd as password,1 as enabled from member where email = ?" authorities-by-username-query="select email as username,authority from authorities where email = ?" /> <password-encoder hash="bcrypt" /> </authentication-provider> </authentication-manager>
The <password-encoder hash="bcrypt" /> tells Spring to use BCryptPasswordEncoder, which implements the PasswordEncoder interface and uses the bcrypt algorithm.
If you try to log in as [email protected]/1111 after rerunning Tomcat, the login will fail because the unencrypted password, 1111, is stored in the member table.
Delete all data of authorities and member tables.
sqlplus java/school delete from authorities; delete from member; commit;
Sign up again with email [email protected] and password 1111.
Even if you try to log in again after signing up, you cannot log in because the system stores the password in plain text 1111 in the member table.
Modify the UserServiceImpl class to encrypt and store passwords.
UserServiceImpl.java
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; @Service public class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; @Autowired private BCryptPasswordEncoder bcryptPasswordEncoder; @Override public void addUser(User user) { user.setPasswd(this.bcryptPasswordEncoder.encode(user.getPasswd())); userMapper.insert(user); } //..omit.. }
Recompile it (mvn clean compile war: inplace) and rerun Tomcat. This time the application is not loaded. Tomcat log tells the reason for the loading failure is that Spring can not inject BCryptPasswordEncoder into UserServiceImpl. If you want Spring to reference the BCryptPasswordEncoder outside the Authentication Provider, you must modify the password encoder configuration below.
security.xml
<beans:bean id="bcryptPasswordEncoAccess Deniedder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder" /> <authentication-manager> <authentication-provider> <jdbc-user-service data-source-ref="dataSource" users-by-username-query="select email as username,passwd as password,1 as enabled from member where email = ?" authorities-by-username-query="select email as username,authority from authorities where email = ?" /> <password-encoder ref="bcryptPasswordEncoder" /> </authentication-provider> </authentication-manager>
Restart Tomcat and try to sign up. This time, SQLException occurs because of the length of the passwd column in the member table. Increase the passwd column of the member table as shown below.
Oracle
alter table member modify passwd varchar2(200);
MySQL
alter table member modify passwd varchar(200) not null;
Delete all data of authorities and member tables and sign up with email [email protected] and password 1111.
If the login succeeds, update the following methods.
UsersController.java
@RequestMapping(value="/bye", method=RequestMethod.POST) public String bye(String email, String passwd, HttpServletRequest req) throws ServletException { User user = new User(); user.setEmail(email); user.setPasswd(passwd); userService.bye(user); req.logout(); return "redirect:/users/bye_confirm"; }
UserServiceImpl.java
@Override public int editAccount(User user) { String encodedPassword = this.getUser(user.getEmail()).getPasswd(); boolean check = this.bcryptPasswordEncoder.matches(user.getPasswd(), encodedPassword); if (check == false) { throw new AccessDeniedException("The current password is incorrect."); } user.setPasswd(encodedPassword); return userMapper.update(user); } @Override public int changePasswd(String currentPasswd, String newPasswd, String email) { String encodedPassword = this.getUser(email).getPasswd(); boolean check = this.bcryptPasswordEncoder.matches(currentPasswd, encodedPassword); if (check == false) { throw new AccessDeniedException("The current password is incorrect."); } newPasswd = this.bcryptPasswordEncoder.encode(newPasswd); return userMapper.updatePasswd(encodedPassword, newPasswd, email); } @Override public void bye(User user) { String encodedPassword = this.getUser(user.getEmail()).getPasswd(); boolean check = this.bcryptPasswordEncoder.matches(user.getPasswd(), encodedPassword); if (check == false) { throw new AccessDeniedException("The current password is incorrect."); } userMapper.deleteAuthority(user.getEmail()); userMapper.delete(user); }
The login(String email, String passwd) method of UserService class is unnecessary, so remove it.