Spring-Security 实现黑白名单功能

添加该功能是在原有功能上新增功能: 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;

 

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spring Security是一个功能强大的安全框架,用于在Java应用程序中实现身份验证和授权。在Spring Security中,可以使用不同的策略来实现授权,包括基于角色的授权、基于资源的授权等。 在Spring Security中,Token授权是一种常用的授权策略。Token授权是一种基于令牌的授权机制,它通过使用令牌来验证用户的身份和访问权限。具体实现中,通常使用JWT(JSON Web Token)作为令牌的格式。 在使用Token授权时,用户首先需要通过身份验证来获取一个令牌。一旦身份验证成功,服务器会生成一个令牌,并将其返回给客户端。客户端在以后的每个请求中都需要携带这个令牌作为身份验证的凭证。服务器在收到请求后,会验证令牌的有效性,并根据令牌中的权限信息来授权用户的访问请求。 Spring Security提供了一些相关的类和配置支持来实现Token授权。其中包括: 1. `JwtTokenProvider`:用于生成和验证JWT令牌的工具类。 2. `JwtAuthenticationFilter`:用于在请求中解析JWT令牌,并验证用户身份。 3. `JwtAuthorizationFilter`:用于验证请求中的JWT令牌,并根据令牌中的权限信息进行授权。 4. `SecurityConfig`:用于配置Spring Security的相关设置,包括Token授权的配置。 通过配置以上类和相关的配置项,可以实现基于Token的授权机制。使用Token授权的好处是可以降低服务器的负载,减少数据库查询操作,并且可以灵活地管理和撤销用户的访问权限。同时,Token授权也提高了系统的安全性,因为令牌中包含了用户的身份和权限信息,所以只有具有有效令牌的用户才能进行授权操作。 总的来说,Spring Security的Token授权提供了一种方便、灵活和安全的授权机制,可以帮助开发人员实现应用程序的身份验证和访问控制。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值