Spring Security自定義用戶認證


具體代碼地址 https://gitee.com/chuzhuyong/HandleSafer

自定義用戶認證

  通過自定義WebSecurityConfigurerAdapter類型的Bean組件,並重寫configure(Authentication ManagerBuilder auth)方法,

可以實現自定義用戶認證。

一、內存身份認證

  In-Memory Authentication(內存身份認證)是最簡單的身份認證方式,主要用於Security安全認證體驗和測試

1.自定義WebSecurityConfigurerAdapter配置類

 

 2.使用內存進行身份認證

 

//開啟MVC Security安全支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 密碼需要設置編碼器
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        // 1、使用內存用戶信息,作為測試使用
        auth.inMemoryAuthentication().passwordEncoder(encoder)
                .withUser("czy").password(encoder.encode("123")).roles("common")
                .and()
                .withUser("tom").password(encoder.encode("456")).roles("vip");
    }
}

 

 3.效果測試

 

 輸入正確的用戶名和密碼后進入首頁

 

 輸入錯誤的用戶名或者密碼,將會顯示錯誤

二、JDBC身份認證

1.數據准備

創建t_customer、t_authority和t_customer_authority三張表

# 選擇使用數據庫
USE springbootdata;
# 創建表t_customer並插入相關數據
DROP TABLE IF EXISTS `t_customer`;
CREATE TABLE `t_customer` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `username` varchar(200) DEFAULT NULL,
  `password` varchar(200) DEFAULT NULL,
  `valid` tinyint(1) NOT NULL DEFAULT '1',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer` VALUES ('1', 'shitou', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
INSERT INTO `t_customer` VALUES ('2', '李四', '$2a$10$5ooQI8dir8jv0/gCa1Six.GpzAdIPf6pMqdminZ/3ijYzivCyPlfK', '1');
# 創建表t_authority並插入相關數據
DROP TABLE IF EXISTS `t_authority`;
CREATE TABLE `t_authority` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `authority` varchar(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8;
INSERT INTO `t_authority` VALUES ('1', 'ROLE_common');
INSERT INTO `t_authority` VALUES ('2', 'ROLE_vip');
# 創建表t_customer_authority並插入相關數據
DROP TABLE IF EXISTS `t_customer_authority`;
CREATE TABLE `t_customer_authority` (
  `id` int(20) NOT NULL AUTO_INCREMENT,
  `customer_id` int(20) DEFAULT NULL,
  `authority_id` int(20) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8;
INSERT INTO `t_customer_authority` VALUES ('1', '1', '1');
INSERT INTO `t_customer_authority` VALUES ('2', '2', '2');
SQL

2.添加JDBC連接數據庫的依賴啟動器

 

 3、數據庫連接配置

#MySQL相關配置
spring.datasource.url=jdbc:mysql://192.168.152.120:3306/springbootdata?serverTimeZone=UTC
spring.datasource.username=root
spring.datasource.password=1
#Redis相關配置
spring.redis.host=192.168.152.120
spring.redis.port=6379
spring.redis.password=1

4、使用JDBC進行身份認證

 

 

 // 2.使用JDBC進行身份驗證
        String userSQL ="select username,password,valid from t_customer "+ "where username = ?";
        String authoritySQL="select c.username,a.authority from t_customer c, "+"t_authority     a,t_customer_authority ca where "+"ca.customer_id=c.id and ca.authority_id=a.id and     c.username =?";
        auth.jdbcAuthentication().passwordEncoder(encoder).dataSource(dataSource)
                .usersByUsernameQuery(userSQL).authoritiesByUsernameQuery(authoritySQL);

5、效果測試:同理

三、UserDetailsService身份認證

1、定義查詢用戶及角色信息的服務接口

 

 

package com.uos.safe.service;

import com.uos.safe.domain.Authority;
import com.uos.safe.domain.Customer;
import com.uos.safe.repository.AuthorityRepository;
import com.uos.safe.repository.CustomerRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import java.util.List;

//對用戶數據結合Redis緩存進行業務處理
@Service
public class CustomerService {
    @Autowired
    private CustomerRepository customerRepository;
    @Autowired
    private AuthorityRepository authorityRepository;
    @Autowired
    private RedisTemplate redisTemplate;

    //業務控制:使用唯一用戶名查詢用戶信息
    public Customer getCustomer(String username){
        Customer customer = null;
        Object o = redisTemplate.opsForValue().get("customer_"+username);
        if (o != null){
            customer = (Customer) o;
        }else {
            customer = customerRepository.findByUsername(username);
            if (customer != null){
                redisTemplate.opsForValue().set("customer_"+username,customer);
            }
        }
        return customer;
    }
    // 業務控制:使用唯一用戶名查詢用戶權限
    public List<Authority> getCustomerAuthority(String username){
        List<Authority> authorities = null;
        Object o = redisTemplate.opsForValue().get("authorities_"+username);
        if (o != null){
            authorities = (List<Authority>) o;
        }else {
            authorities = authorityRepository.findAuthoritiesByUsername(username);
            if (authorities.size() > 0){
                redisTemplate.opsForValue().set("authorities_"+username,authorities);
            }
        }
        return authorities;
    }
}
CustomerService

2、定義UserDetailsService用於封裝認證用戶信息

 

 

package com.uos.safe.service;

import com.uos.safe.domain.Authority;
import com.uos.safe.domain.Customer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

 /*自定義一個 UserDetailsService實現類進行用戶認證信息封裝*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    CustomerService customerService;
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 通過業務方法獲取用戶權限信息
        Customer customer = customerService.getCustomer(s);
        List<Authority> authorities = customerService.getCustomerAuthority(s);
        // 對用戶權限進行封裝
        List<SimpleGrantedAuthority> list = authorities.stream()
                .map(authority -> new SimpleGrantedAuthority(authority.getAuthority()))
                .collect(Collectors.toList());
        // 返回封裝的UserDetails用戶詳情類
        if (customer != null) {
            UserDetails userDetails = new User(customer.getUsername(),customer.getPassword(),list);
            return userDetails;
        } else {
          // 如果查詢的用戶不存在(用戶名不存在),必須拋出異常
          throw new UsernameNotFoundException("當前用戶不存在!");
        }
    }
}
UserDetailsServiceImpl

3、使用UserDetailsService進行身份認證

 

 4、效果測試:同理


免責聲明!

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



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