Spring-Security 实现黑白名单功能分析

无情 阅读:229 2021-03-31 17:19:54 评论:0

添加该功能是在原有功能上新增功能: SpringBoot +SpringSecurity+mysql 实现用户数据权限管理

本文仅做重点代码的和相关依赖说明:SpringBoot +SpringSecurity+mysql 实现用户数据权限管理 文章中,我们采用的了分布式架构搭建该项目,导致controller 模块是不存在数据库连接资源(DataSource),由此,我们在controller 模块需要添加关于mysql 的连接和相关配置参数:
 

	<!-- mysql数据库驱动 --> 
		<dependency> 
			<groupId>mysql</groupId> 
			<artifactId>mysql-connector-java</artifactId> 
			<version>8.0.12</version> 
		</dependency> 
		<!-- 数据层 Spring-data-jpa --> 
		<dependency> 
			<groupId>org.springframework.boot</groupId> 
			<artifactId>spring-boot-starter-data-jpa</artifactId> 
		</dependency>

application.properties 添加数据库相关配置参数:

#mysql setting 
spring.datasource.url=jdbc:mysql://192.168.1.73:3306/boot-security?serverTimezone=UTC&useSSL=false&allowPublicKeyRetrieval=true 
spring.datasource.username=root 
spring.datasource.password=digipower 
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver 
spring.jpa.properties.hibernate.hbm2ddl.auto=update

自定义IP黑白名单相关实体文件和查询接口:

package com.zzg.security.ip; 
 
import java.io.Serializable; 
import java.util.Date; 
 
 
/** 
 * 黑白IP对象 
 * @author zzg 
 * 
 */ 
@SuppressWarnings("serial") 
public class IpRoster implements Serializable { 
	 
	private Long id; 
	 
	private String ip; 
	 
	private Date date; 
	 
	public IpRoster(){ 
		super(); 
	} 
 
	// 构造函数 
	public IpRoster(Long id, String ip, Date date) { 
		super(); 
		this.id = id; 
		this.ip = ip; 
		this.date = date; 
	} 
	 
	// set 和 get 方法 
	public Long getId() { 
		return id; 
	} 
 
	public void setId(Long id) { 
		this.id = id; 
	} 
 
	public String getIp() { 
		return ip; 
	} 
 
	public void setIp(String ip) { 
		this.ip = ip; 
	} 
 
	public Date getDate() { 
		return date; 
	} 
 
	public void setDate(Date date) { 
		this.date = date; 
	} 
 
} 
 
package com.zzg.security.ip; 
 
import java.sql.ResultSet; 
import java.sql.SQLException; 
 
 
import org.springframework.jdbc.core.RowMapper; 
/** 
 * RowMapper 转换IpRoster 实体对象 
 * @author zzg 
 * 
 */ 
public class IpRosterMapper implements RowMapper<IpRoster> { 
 
	@Override 
	public IpRoster mapRow(ResultSet rs, int rowNum) throws SQLException { 
		// TODO Auto-generated method stub 
		IpRoster object = new IpRoster(); 
		object.setId(rs.getLong("id")); 
		object.setIp(rs.getString("ip")); 
		object.setDate(rs.getDate("date")); 
		return object; 
	} 
 
} 
package com.zzg.security.ip; 
 
import java.util.List; 
import org.springframework.jdbc.core.support.JdbcDaoSupport; 
 
/** 
 * IP黑白名单数据库查询 
 * @author zzg 
 * 
 */ 
public class IpRosterRepositoryImpl extends JdbcDaoSupport { 
	public static final String DEF_SELECT_IP_SQL ="select id, ip, date from ip_roster"; 
	 
	public List<IpRoster> getAllIpRoster(){ 
		return getJdbcTemplate().query(DEF_SELECT_IP_SQL, new IpRosterMapper()); 
		 
	} 
 
} 

自定义认证器,添加验证用户IP是否在黑白名单中:

package com.zzg.security.provider; 
 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.stream.Collectors; 
 
import javax.sql.DataSource; 
 
import org.apache.commons.codec.digest.DigestUtils; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.security.authentication.AuthenticationProvider; 
import org.springframework.security.authentication.BadCredentialsException; 
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException; 
import org.springframework.security.core.userdetails.UserDetailsService; 
import org.springframework.security.core.userdetails.UsernameNotFoundException; 
import org.springframework.security.web.authentication.WebAuthenticationDetails; 
import org.springframework.stereotype.Component; 
 
import com.zzg.security.ip.IpRoster; 
import com.zzg.security.ip.IpRosterRepositoryImpl; 
import com.zzg.security.userservice.AuthUserDetails; 
import com.zzg.security.userservice.CustomUserService; 
 
/** 
 *自定义身份验证提供者 
 *  
 * @author zzg 
 * 
 */ 
@Component 
public class SpringSecurityProvider implements AuthenticationProvider { 
 
	@Autowired 
	private CustomUserService userDetailService; 
	 
	@Autowired 
	private DataSource dataSource; // 数据源 
	 
	private IpRosterRepositoryImpl ip; // IP 黑白名单查询 
	 
	private List<String> black_white = new ArrayList<>(); 
	 
	 
 
 
	@Override 
	public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
		// TODO Auto-generated method stub 
		// 检查用户IP 
	    WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails(); 
        String userIp = details.getRemoteAddress(); 
         
        // 黑白名单初始化数据 
        if(ip == null){ 
			ip = new IpRosterRepositoryImpl(); 
			ip.setDataSource(dataSource); // 设定数据源 
		} 
		List<IpRoster> list = ip.getAllIpRoster(); 
		if(list != null && list.size() > 0){ 
			black_white = list.stream().map(IpRoster::getIp).collect(Collectors.toList()); 
		} 
		 
        // 判断用户IP 是否在黑白名单中 
        if(black_white.contains(userIp)){ 
            throw new BadCredentialsException("非法 IP 地址"); 
        } 
         
		 
		String userName = authentication.getName(); 
		String password = (String) authentication.getCredentials(); 
 
	    // 查询用户权限信息 
		AuthUserDetails userInfo = (AuthUserDetails) userDetailService.loadUserByUsername(userName);  
		if (userInfo == null) { 
			throw new UsernameNotFoundException(""); 
		} 
 
		// 密码判断 
		String encodePwd = DigestUtils.md5Hex(password).toUpperCase(); 
		if (!userInfo.getPassword().equals(encodePwd)) { 
			throw new BadCredentialsException(""); 
		} 
 
		return new UsernamePasswordAuthenticationToken(userInfo, userInfo.getPassword(), 
				userInfo.getAuthorities()); 
	} 
 
	@Override 
	public boolean supports(Class<?> authentication) { 
		// TODO Auto-generated method stub 
		return UsernamePasswordAuthenticationToken.class.equals(authentication); 
	} 
	 
	// 拓展获取用户查询服务 
	public UserDetailsService getUserDetailsService(){ 
		return this.userDetailService; 
	} 
} 

补全黑白名单的SQL脚本:

DROP TABLE IF EXISTS `persistent_logins`; 
CREATE TABLE `persistent_logins`  ( 
  `username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 
  `series` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 
  `token` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, 
  `last_used` timestamp(0) NOT NULL DEFAULT CURRENT_TIMESTAMP(0) ON UPDATE CURRENT_TIMESTAMP(0), 
  PRIMARY KEY (`series`) USING BTREE 
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;

 

声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

发表评论
搜索
KIKK导航

KIKK导航

排行榜
关注我们

一个IT知识分享的公众号