Spring Security 3 (三) 用户数据存放于数据库
上章回顾:
上一章中,我们将用户名、密码以及用户对应的角色都配置于applicationContext-security.xml中,基本实现了我们能控制用户的访问权限。但是在现实开发中,我们不可能将用户信息硬编码在配置文件中,通常我们都是存放到数据中。同时我们应该对用户的密码进行加密存储。
目标:
1.将用户信息存放于数据库
2.对用户的密码进行加密
详细操作:
1.其他代码参考上一章中代码。本章中,首先我们要创建一张数据表来记录我们的用户信息。SpringSecurity提供的验证机制中,首先我们自定义的Entity类要实现UserDetails,并且要实现他接口中的几个方法,下面来看具体代码:
@SuppressWarnings("serial") @Entity(name = "User") @Table(name = "userinfo") public class User implements UserDetails { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id", unique = true, nullable = false) private int id; @Column(name = "username") private String username; @Column(name = "password") private String password; @Column(name = "role") private String role; @Column(name = "enabled") private boolean enabled = false; @Column(name = "salt_value") private String salt_value; public int getId() { return id; } public void setId(int id) { this.id = id; } public void setUsername(String username) { this.username = username; } public void setPassword(String password) { this.password = password; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } @Override public Collection<? extends GrantedAuthority> getAuthorities() { List<GrantedAuthority> list = new ArrayList<GrantedAuthority>(); System.out.println("User‘s role: " + getRole()); list.add(new SimpleGrantedAuthority(getRole())); return list; } @Override public String getPassword() { return this.password; } @Override public String getUsername() { // TODO Auto-generated method stub return this.username; } @Override public boolean isAccountNonExpired() { // TODO 根据需要修改 return true; } @Override public boolean isAccountNonLocked() { // TODO Auto-generated method stub return true; } @Override public boolean isCredentialsNonExpired() { // TODO Auto-generated method stub return true; } @Override public boolean isEnabled() { // TODO Auto-generated method stub return this.enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public String getSalt_value() { return salt_value; } public void setSalt_value(String salt_value) { this.salt_value = salt_value; } }
首先,getAuthorities()方法,我们需要返回用户的角色集合,但是由于我们为了方便,一个用户就只定义了一个角色。实际开发中,我们可以换成List,然后再来添加到对应的集合中。
剩下几个@Override的方法,都是接口中需要我们必须实现的方法,因为在SpringSecurity去判断用户是否能登录,是否有权限去访问某些资源的时候就是通过这几个属性去判断的,所以我们根据自己的需求来进行返回值。而且每个方法名称已经写的明确代表的意思。
2.Entity建立好之后,我们再来建立我们的数据。这里直接贴出代码:
DROP TABLE IF EXISTS `userinfo`; CREATE TABLE `userinfo` ( `id` int(11) NOT NULL AUTO_INCREMENT, `username` varchar(20) DEFAULT NULL, `password` varchar(255) DEFAULT NULL, `role` varchar(20) DEFAULT NULL, `enabled` tinyint(1) DEFAULT NULL, `salt_value` varchar(50) DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
3.Spring Security如何来验证我们的用户呢?按照我们自己的思路来看,应该是:查找用户是否在我们的数据库中->验证用户密码->判断用户是否可用->其他判断->用户是否登录成功。在此本实例中,我们已经在SpringSecurity配置文件中配置了访问资源的权限,因此在此我们只需用找到该用户,然后返回给SpringSecurity的处理器,让他自己来处理。所以我们要实现SpringSecurity提供的UserDetailsService接口:
public interface UserService extends UserDetailsService{ } @Service(value = "userService") public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { System.out.println("find the user name: " + username); User user = userDao.getUserByUserName(username); System.out.println(user == null); if (user == null) { System.out.println("username can‘t found"); throw new UsernameNotFoundException("Username not found..."); } return user; } }
4.到此,基本已经搞定。现在我们只需用修改配置文件,告诉SpringSecurity按照我们自己定义的方法来实现,修改applicationContext-security.xml:
<authentication-manager> <authentication-provider user-service-ref="userService"> <password-encoder ref="passwordEncoder"> <salt-source ref="saltSource"/> </password-encoder> </authentication-provider> </authentication-manager> <!-- 密码盐值,取用户名作为盐值 --> <!-- userPropertyToUse:主要用来将我们的对象放入到他的方法中,根据这个属性名称取出盐值 --> <beans:bean id="saltSource" class="org.springframework.security.authentication.dao.ReflectionSaltSource"> <beans:property name="userPropertyToUse" value="salt_value"></beans:property> </beans:bean> <!-- SHA加密类 --> <beans:bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"> </beans:bean>
我们通过使用SpringSecurity提供的加密方法进行加密,同时我们增加盐值在密码中,这样让破解失效。
authentication-provider中user-service-ref,就是我们上一点中自定义的service类。同时我们提供加密方式。
5.在此我们有一个问题,如果我们手工的加入数据到数据库中,密码是明文,没有进行加密的。为了我们能够顺利登陆,我们设计一个注册用户的页面,用来注册用户。注册用户页面我们就自己发挥了,主要传递到后台的数据包括:用户名、密码、角色。此点主要是看看如何对密码进行加密:
/** * 注入两个工具类 */ @Resource private ReflectionSaltSource saltSource; @Resource private ShaPasswordEncoder passwordEncoder; /** * 注册用户 * @param user * @return */ @RequestMapping("/register") public ModelAndView register(User user) { user.setEnabled(true); // 使用系统当前时间作为盐值 user.setSalt_value(System.currentTimeMillis() + ""); // 加密密码:原有密码+盐值。盐值通过从user对象中获取,我们在配置中有写到查找哪个属性 String password = passwordEncoder.encodePassword(user.getPassword(), saltSource.getSalt(user)); user.setPassword(password); if (userDao.addUser(user)) { System.out.println("register success"); } else { System.out.println("failed"); } return new ModelAndView("redirect:/login.jsp"); }
6.好了,用户我们注册成功,可以直接跳转到登录页面,用刚才注册的用户名和密码进行登录,并进行权限测试。
本文出自 “SG-YYZ” 博客,请务必保留此出处http://sgyyz.blog.51cto.com/5069360/1409098