JavaWeb-SpringSecurity在數據庫中查詢登陸用戶


 

 

  系列博文

  項目已上傳至guthub  傳送門

  JavaWeb-SpringSecurity初認識  傳送門

  JavaWeb-SpringSecurity在數據庫中查詢登陸用戶  傳送門

  JavaWeb-SpringSecurity自定義登陸頁面  傳送門

  JavaWeb-SpringSecurity實現需求-判斷請求是否以html結尾  傳送門

  JavaWeb-SpringSecurity自定義登陸配置  傳送門

  JavaWeb-SpringSecurity圖片驗證ImageCode  傳送門

  JavaWeb-SpringSecurity記住我功能  傳送門

  JavaWeb-SpringSecurity使用短信驗證碼登陸  傳送門

 

 

  在MySQL數據庫中創建springsecurity數據庫

  

 

 

   (id、username、password都是根據User.java映射過來的)

 

  在application.properties中編寫配置文件

#datasource
spring.datasource.url=jdbc:mysql:///springsecurity?serverTimezone=UTC&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.dricer-class-name=com.mysql.jdbc.Driver

#jpa
#打印出數據庫語句
spring.jpa.show-sql=true
#更新數據庫表
spring.jpa.hibernate.ddl-auto=update

 

  創建domain實體層User.java和repository存儲層接口UserRepository.java  

  書寫用戶User.java實體

    //用戶是否沒有失效
    @Transient
    private boolean accountNonExpried;
    //用戶是否凍結
    @Transient
    private boolean accountNonLocked;
    //證明是否過期
    @Transient
    private boolean credentialsNonExpired;
    //判斷是否刪除
    @Transient
    private boolean enabled;
    @Transient
    //添加    @Transient 注解可以不將  Set<GrantedAuthority>映射到數據庫表上
    private Set<GrantedAuthority> authorities;


//給hibernatre用的構造方法
    protected User() {
        
    }
    
    public User(Long id,String username,String password)
    {
        this.id = id;
        this.username = username;
        this.password = password;
    }
    
    //給SpringSecurity用的構造方法
    public User(String username,String password,
            Collection<? extends GrantedAuthority> authorities) {
            this(username,password,true,true,true,true,authorities);
    }
    
    public User(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpried = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
    
    private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
    
    private static class AuthorityComparator implements Comparator<GrantedAuthority>,
    Serializable {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    public int compare(GrantedAuthority g1, GrantedAuthority g2) {
    // Neither should ever be null as each entry is checked before adding it to
    // the set.
    // If the authority is null, it is a custom authority and should precede
    // others.
    if (g2.getAuthority() == null) {
        return -1;
    }

    if (g1.getAuthority() == null) {
        return 1;
    }

    return g1.getAuthority().compareTo(g2.getAuthority());
    }
    }

 

package com.Gary.GaryRESTful.domain;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Transient;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

@Entity
public class User implements UserDetails{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    
    //用戶是否沒有失效
    @Transient
    private boolean accountNonExpried;
    //用戶是否凍結
    @Transient
    private boolean accountNonLocked;
    //證明是否過期
    @Transient
    private boolean credentialsNonExpired;
    //判斷是否刪除
    @Transient
    private boolean enabled;
    @Transient
    //添加    @Transient 注解可以不將  Set<GrantedAuthority>映射到數據庫表上
    private Set<GrantedAuthority> authorities;
    
    //給hibernatre用的構造方法
    protected User() {
        
    }
    
    public User(Long id,String username,String password)
    {
        this.id = id;
        this.username = username;
        this.password = password;
    }
    
    //給SpringSecurity用的構造方法
    public User(String username,String password,
            Collection<? extends GrantedAuthority> authorities) {
            this(username,password,true,true,true,true,authorities);
    }
    
    public User(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpried = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
    
    private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
    
    private static class AuthorityComparator implements Comparator<GrantedAuthority>,
    Serializable {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    public int compare(GrantedAuthority g1, GrantedAuthority g2) {
    // Neither should ever be null as each entry is checked before adding it to
    // the set.
    // If the authority is null, it is a custom authority and should precede
    // others.
    if (g2.getAuthority() == null) {
        return -1;
    }

    if (g1.getAuthority() == null) {
        return 1;
    }

    return g1.getAuthority().compareTo(g2.getAuthority());
    }
    }
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    //用戶權限
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return authorities;
    }
    
    //用戶是否沒有失效
    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return accountNonExpried;
    }
    
    //用戶是否被凍結
    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return accountNonLocked;
    }
    
    //用戶是否證明權限過期
    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return credentialsNonExpired;
    }
    
    //判斷用戶是否刪除
    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return enabled;
    }
    
    
    
}
User.java

 

  完善User.java實體

    public User(Long id,String username,String password)
    {
        this.id = id;
        this.username = username;
        this.password = password;
    }
    
    //給SpringSecurity用的構造方法
    public User(String username,String password,
            Collection<? extends GrantedAuthority> authorities) {
            this(username,password,true,true,true,true,authorities);
    }
    
    public User(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpried = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
    
    private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
    
    private static class AuthorityComparator implements Comparator<GrantedAuthority>,
    Serializable {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    public int compare(GrantedAuthority g1, GrantedAuthority g2) {
    // Neither should ever be null as each entry is checked before adding it to
    // the set.
    // If the authority is null, it is a custom authority and should precede
    // others.
    if (g2.getAuthority() == null) {
        return -1;
    }

    if (g1.getAuthority() == null) {
        return 1;
    }

    return g1.getAuthority().compareTo(g2.getAuthority());
    }
    }

 

package com.Gary.GaryRESTful.domain;

import java.io.Serializable;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityCoreVersion;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.util.Assert;

@Entity
public class User implements UserDetails{

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String username;
    private String password;
    
    //用戶是否沒有失效
    private boolean accountNonExpried;
    //用戶是否凍結
    private boolean accountNonLocked;
    //證明是否過期
    private boolean credentialsNonExpired;
    //判斷是否刪除
    private boolean enabled;
    private Set<GrantedAuthority> authorities;
    
    //給hibernatre用的構造方法
    protected User() {
        
    }
    
    public User(Long id,String username,String password)
    {
        this.id = id;
        this.username = username;
        this.password = password;
    }
    
    //給SpringSecurity用的構造方法
    public User(String username,String password,
            Collection<? extends GrantedAuthority> authorities) {
            this(username,password,true,true,true,true,authorities);
    }
    
    public User(String username, String password, boolean enabled,
            boolean accountNonExpired, boolean credentialsNonExpired,
            boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {

        if (((username == null) || "".equals(username)) || (password == null)) {
            throw new IllegalArgumentException(
                    "Cannot pass null or empty values to constructor");
        }

        this.username = username;
        this.password = password;
        this.enabled = enabled;
        this.accountNonExpried = accountNonExpired;
        this.credentialsNonExpired = credentialsNonExpired;
        this.accountNonLocked = accountNonLocked;
        this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
    }
    
    private static SortedSet<GrantedAuthority> sortAuthorities(
            Collection<? extends GrantedAuthority> authorities) {
        Assert.notNull(authorities, "Cannot pass a null GrantedAuthority collection");
        // Ensure array iteration order is predictable (as per
        // UserDetails.getAuthorities() contract and SEC-717)
        SortedSet<GrantedAuthority> sortedAuthorities = new TreeSet<>(
                new AuthorityComparator());

        for (GrantedAuthority grantedAuthority : authorities) {
            Assert.notNull(grantedAuthority,
                    "GrantedAuthority list cannot contain any null elements");
            sortedAuthorities.add(grantedAuthority);
        }

        return sortedAuthorities;
    }
    
    private static class AuthorityComparator implements Comparator<GrantedAuthority>,
    Serializable {
    private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;

    public int compare(GrantedAuthority g1, GrantedAuthority g2) {
    // Neither should ever be null as each entry is checked before adding it to
    // the set.
    // If the authority is null, it is a custom authority and should precede
    // others.
    if (g2.getAuthority() == null) {
        return -1;
    }

    if (g1.getAuthority() == null) {
        return 1;
    }

    return g1.getAuthority().compareTo(g2.getAuthority());
    }
    }
    
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    
    //用戶權限
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // TODO Auto-generated method stub
        return authorities;
    }
    
    //用戶是否沒有失效
    @Override
    public boolean isAccountNonExpired() {
        // TODO Auto-generated method stub
        return accountNonExpried;
    }
    
    //用戶是否被凍結
    @Override
    public boolean isAccountNonLocked() {
        // TODO Auto-generated method stub
        return accountNonLocked;
    }
    
    //用戶是否證明權限過期
    @Override
    public boolean isCredentialsNonExpired() {
        // TODO Auto-generated method stub
        return credentialsNonExpired;
    }
    
    //判斷用戶是否刪除
    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return enabled;
    }
    
    
    
}
User.java

 

  完善UserRepository.java接口,實現查找用戶姓名方法

    @Query(value = "select * from user where username = ?1",nativeQuery = true)
    User findUserByUsername(String username);

 

  在UserService.java中實現查找用戶Service

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private UserRepository userRepository;
    
    //spring security默認處理登陸(username為輸入的username)
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        //System.out.println(username);
        User user = userRepository.findUserByUsername(username);
        //用戶名,密碼,權限
        //User實現UserDetails接口
        return new User(username,passwordEncoder.encode(user.getPassword()),AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }

 

  測試時發現,當用戶輸入錯誤的用戶名和密碼時,控制台會報空指針異常,前台為給出“壞的憑證”給用戶提示信息。

  原因:springsecurity會攔截一切其它的請求。只有當用戶輸入正確的用戶名和密碼,springsecurity才會釋放用戶正常的請求。

 

package com.Gary.GaryRESTful.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;


//Web應用安全適配器
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    //告訴SpringSecurity密碼用什么加密的
    @Bean
    public PasswordEncoder passwordEncoder()
    {
        return new BCryptPasswordEncoder();
    }
    
    
    //表單驗證(身份認證)
    protected void configure(HttpSecurity http) throws Exception{
        http.formLogin()
            .and()
            //請求授權
            .authorizeRequests()
            //所有請求都被攔截,跳轉到(/login請求中)
            .anyRequest()
            //都需要我們身份認證
            .authenticated();
    }
    
}
SecurityConfig.java

 

package com.Gary.GaryRESTful.repository;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;

import com.Gary.GaryRESTful.domain.User;

public interface UserRepository extends CrudRepository<User,Long>{

    @Query(value = "select * from user where username = ?1",nativeQuery = true)
    User findUserByUsername(String username);
    
}
UserRepository.java

 

package com.Gary.GaryRESTful.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
//import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.Gary.GaryRESTful.domain.User;
import com.Gary.GaryRESTful.repository.UserRepository;


//用SprinSecurity默認的登陸系統
//UserService要實現UserDetailsService接口
@Component
public class UserService implements UserDetailsService{

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private UserRepository userRepository;
    
    //spring security默認處理登陸(username為輸入的username)
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        //System.out.println(username);
        User user = userRepository.findUserByUsername(username);
        //用戶名,密碼,權限
        //User實現UserDetails接口
        return new User(username,passwordEncoder.encode(user.getPassword()),AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }

    
    
}
UserService.java

 

  所以我們可以在UserDetails.java中進行修改,添加判斷,如果在數據庫中未查詢到用戶時返回null

  @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        //System.out.println(username);
        User user = userRepository.findUserByUsername(username);
        //用戶名,密碼,權限
        if(user == null)
        {
            throw new UsernameNotFoundException(username);
        }
        //User實現UserDetails接口
        return new User(username,passwordEncoder.encode(user.getPassword()),AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }

 

 

package com.Gary.GaryRESTful.service;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
//import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import com.Gary.GaryRESTful.domain.User;
import com.Gary.GaryRESTful.repository.UserRepository;


//用SprinSecurity默認的登陸系統
//UserService要實現UserDetailsService接口
@Component
public class UserService implements UserDetailsService{

    @Autowired
    private PasswordEncoder passwordEncoder;
    
    @Autowired
    private UserRepository userRepository;
    
    //spring security默認處理登陸(username為輸入的username)
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // TODO Auto-generated method stub
        //System.out.println(username);
        User user = userRepository.findUserByUsername(username);
        //用戶名,密碼,權限
        if(user == null)
        {
            throw new UsernameNotFoundException(username);
        }
        //User實現UserDetails接口
        return new User(username,passwordEncoder.encode(user.getPassword()),AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
    }

    
    
}
UserService.java

 

  拓展:根據SpringSecurity提供的User方法

    //給SpringSecurity用的構造方法
    public User(String username,String password,
            Collection<? extends GrantedAuthority> authorities) {
            this(username,password,true,true,true,true,authorities);
    }

 

  可以在UserService.java中提供的UserDetails返回值中添加4個boolean值

return new User(user.getUsername(),passwordEncoder.encode(user.getPassword()),true,true,true,true,AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));

 

  這四個boolean值代表着

        //用戶是否沒有失效
    @Transient
    private boolean accountNonExpried;
    //用戶是否凍結
    @Transient
    private boolean accountNonLocked;
    //證明是否過期
    @Transient
    private boolean credentialsNonExpired;
    //判斷是否刪除
    @Transient
    private boolean enabled;    

 

  如果return返回值中四個參數都為true,springscurity不會去進行攔截驗證,

  當其中一個參數為false時,springsecurity就會對用戶進行攔截驗證~

 

 

 

 

 

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM