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-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.好了,用戶我們註冊成功,可以直接跳轉到登錄頁面,用剛纔註冊的用戶名和密碼進行登錄,並進行權限測試。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章