【微服务|Spring Security⑱】spring security授权汇总

4.7.1 概述

授权的方式包括web授权和方法授权,web授权是通过url拦截进行授权,方法授权是通过方法拦截进行授权。他们都会调用accessDecisionManager进行授权决策,若为web授权则拦截器为FilterSecuritylnterceptor;若为方法授权则拦截器为Methodsecurityinterceptor。如果同时通过web授权和方法授权则先执行web授权,再执行方法授权。最后决策通过,则允许访问资源,否则将禁止访问。

4.7.2 准备环境

4.7.2.1 数据库环境

在t_user数据库创建如下表:

角色表:

CREATE TABLE 't_role' (
	'id' varchar(32) NOT NULL,
	'role_name' varchar(255) DEFAULT NULL,
	'description' varchar(255) DEFAULT NULL,
	'create_time' datetime DEFAULT NULL,
	'update_time' datetime DEFAULT NULL,
	'status' char(l) NOT NULL,
	PRIMARY KEY ('id'),
	UNIQUE KEY 'unique_role_name' ('role_name')
)ENGINE=InnoDB DEFAULT CHARSET=utf8

insert into 't_role'('id','role_name', 'description','create_time', ' update_time', 'status') values ('1''管理员',NULL,NULL,NULL)

用户角色关系表:

CREATE TABLE 't_user_role' (
	'userid' varchar(32) NOT NULL,
	'roleid' varchar(32) NOT NULL,
	'create_time' datetime DEFAULT NULL,
	'creator' varchar(255) DEFAULT NULL,
	PRIMARY KEY ('userid','role_id')
)ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into 't_user_role'('user_id','roleid','create_time','creator') values
('1','1',NULL,NULL);

权限表:

CREATE TABLE 't_permission' (
	'id' varchar(32) NOT NULL,
	'code' varchar(32) NOT NULL COMMENT,权限标识符
	'description' varchar(64) DEFAULT NULL COMMENT '描述
	'url' varchar(128) DEFAULT NULL COMMENT '请求地址
	PRIMARY KEY ('id')
)ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into 't_permission' (' id',' code','description',' url') values (' 1’,’ pl','测试资源 l','/r/rl'),('2','p3','测试资源2','/r/r2');

角色权限关系表:

CREATE TABLE 't_role_permission' (
	'roleid' varchar(32) NOT NULL,
	'permission_id' varchar(32) NOT NULL,
	PRIMARY KEY ('role_id','permissionid')
)ENGINE=InnoDB DEFAULT CHARSET=utf8
insert into 't_role_permission'(' role_id','permission_id') values ('1','1')
4.7.2.2 修改 UserDetailService

1、修改dao接口
在UserDao中添加:

〃根据用户id查询用户权限
public List<String> findPermissionsByUserId(String userld){
    
    
	String sql=...List<PermissionDto> list = jdbcTemplate.query(sql,new Object[]{
    
    userid}new BeanPropertyRowMappero(PermissionDto.class));
	List<String> permissions = new ArrayList<>();
	list.iterator().forEachRemaining(c->permissions.add(c.getCode())); 
	return permissions;

2、修改UserDetailService
实现从数据库读取权限

@0verride
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    
     //登录略
	System.out.printin("username="+username);
	//根据账号去数据库查询...
	UserDto user = userDao.getUserByUsername(username);
	if(user == null)(
	return null;
	}
	//查询用户权限
	List<String> permissions = userDao.findPermissionsByUserId(user.getId());
	Stringf] perarray = new String[permissions.size()];
	permissions.toArray(perarray);
	//创建 userDetails
	UserDetails userDetails =
	User.withUsername(user.getFullname()).password(user.getPassword()).authorities(perarray)build(); 
	return userDetails;
}

4.7.2 web授权

在上面例子中我们完成了认证拦截,并对/r/**下的某些资源进行简单的授权保护,但是我们想进行灵活的授权控制该怎么做呢?通过给http.authorizeRequests()添加多个子节点来定制需求 ,如下代码:

@Override
protected void configure(HttpSecurity http) throws Exception {
    
    	
http .authorizeRequests()	(1)
	.antMatchers("/r/rl").hasAuthority("pl")	(2)
	.antMatchers("/r/r2").hasAuthority("p2")	(3)
	.antMatchers("/r/rS").access("hasAuthority('p1') and hasAuthority('p2')")	(4)
	.antMatchers("/r/**")]authenticated()	(5)
	.anyRequest().permitAll().and()
	.formLogin()

}		

(1 ) http.authorizeRequests()方法有多个子节点,每个macher按照他们的声明顺扇丸行。
(2)指定"/r/r1 “URL,拥有p1权限能够访问
(3 )指定”/r/r2"URL ,拥有p2权限能够访问
(4 )指定了”/r/r3”URL ,同时拥有p1和p2权限才能够访问
(5 )指定了除了r1、r2、r3之外’7r/**''资源,同时通过身份认证就能够访问,这里使用SpEL ( Spring Expression Language )表达式。
(6 )剩余的尚未匹配的资源,不做保护。

注意: 规则的顺序是重要的,更具体的规则应该先写.现在以/admin开始的所有内容都需要具有ADMIN角色的身份验证用 户,即使是/
admin / login路径(因为/ admin / login已经被/ admin / **规则匹配,因此第二个规则被忽略).

.antMatchers("/admin/*\*").hasRole("ADMIN")
.antMatchers("/admin/login").permitAll()

因此登录页面的规则应该在/ admin / **规则之前.例如.

.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/*\*").hasRole("ADMIN")

保护URL常用的方法有:

authenticated()保护URL ,需要用户登录 permitAII()指定URL无需保护,一般应用与静态资源文件

hasRole(String role)限制单个角色访问,角色将被增加"ROLE_".所以’ADMIN"将和"ROLE_ADMIN"进行比较.

hasAuthority(String authority)限制单个权限访问

hasAnyRole(String… roles)允许多个角色访问. hasAnyAuthority(String… authorities)允许多个权限访问.

access(String attribute)该方法使用SpEL表达式,所以可以创建复杂的限制.

haslpAddress(String ipaddressExpression)限制IP地址或子网

4.7.3 方法授权

现在我们已经掌握了使用如何使用http.authorizeRequests()对web资源进行授权保护,从Spring Security2.0版本开始,它支持服务层方法的安全性的支持。

@PreAuthorize,@PostAuthorize, @Secured三类注解。

我们可以在任(可@Configuration实例上使用@EnableGlobalMethodSecurity注释来启用基于注解的安全性。

以下内容将启用Spring Security的@Secured注释。

@EnableGlobalMethodSecurity(securedEnabled = true) 
public class MethodSecurityConfig (// ...
}

然后向方法(在类或接口上)添加注解就会限制对该方法的访问。Spring Security的原生注释支持为该方法定义了 一组属性。这些将被传递给AccessDecisionManager以供它作出实际的决定:

public interface BankService {
    
     
	@Secured()
	public Account readAccount(Long id);
	@Secured()
	public Accountf] findAccounts();
	@Secured()
	public Account post(Account account, double amount);
}

以上配置标明readAccount、findAccounts方法可匿名访问,底层使用WebExpressionVoter投票器,可从 AffirmativeBased 第23 行代码跟踪。 post方法需要有TELLER角色才能访问,底层使用RoleVoter投票器。
使用如下代码可启用prePost注解的支持

@EnableGlobalMethodSecurity(prePostEnabled = true) 
public class MethodSecurityConfig {
    
    
//...
}

相应Java代码如下:

public interface BankService {
    
    
	@PreAuthorize("isAnonymous()")
	public Account readAccount(Long id);
	@PreAuthorize("isAnonymous()")
	public Accountf] findAccounts。;
	@PreAuthorize("hasAuthority('p_transfer') and hasAuthority('p_read_account')") public Account post(Account account, double amount);
}

猜你喜欢

转载自blog.csdn.net/CSDN_SAVIOR/article/details/125683428