【微服务|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);
}


原文始发于微信公众号(步尔斯特):【微服务|Spring Security⑱】spring security授权汇总

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/47974.html

(0)
小半的头像小半

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!