首页 > 代码库 > Spring Security 3 (三) 用户数据存放于数据库

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 = http://www.mamicode.com/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 = "http://www.mamicode.com/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="http://www.mamicode.com/salt_value"></beans:property>
    </beans:bean>
    <!-- SHA加密类 -->
    <beans:bean id="passwordEncoder"
        class="org.springframework.security.authentication.encoding.ShaPasswordEncoder">
    </beans:bean>

我们通过使用SpringSecurity提供的加密方法进行加密,同时我们增加盐值在密码中,这样让破解失效。

authentication-provideruser-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