• 博客园logo
  • 会员
  • 周边
  • 新闻
  • 博问
  • 闪存
  • 赞助商
  • Chat2DB
    • 搜索
      所有博客
    • 搜索
      当前博客
  • 写随笔 我的博客 短消息 简洁模式
    用户头像
    我的博客 我的园子 账号设置 会员中心 简洁模式 ... 退出登录
    注册 登录
南轲梦
博客园    首页    新随笔    联系   管理    订阅  订阅

自定义Spring Security权限控制管理(实战篇)

上篇《话说Spring Security权限管理(源码)》介绍了Spring Security权限控制管理的源码及实现,然而某些情况下,它默认的实现并不能满足我们项目的实际需求,有时候需要做一些自己的实现,本次将围绕上次的内容进行一次项目实战。

实战背景

背景描述

项目中需要做细粒的权限控制,细微至url + httpmethod (满足restful,例如: https://.../xxx/users/1 , 某些角色只能查看(HTTP GET), 而无权进行增改删(POST, PUT, DELETE))。

表设计

为避嫌,只列出要用到的关键字段,其余敬请自行脑补。

  1. admin_user 管理员用户表, 关键字段( id, role_id )。
  2. t_role 角色表, 关键字段( id, privilege_id )。
  3. t_privilege 权限表, 关键字段( id, url, method )

三个表的关联关系就不用多说了吧,看字段一眼就能看出。

实现前分析

我们可以逆向思考:

要实现我们的需求,最关键的一步就是让Spring Security的AccessDecisionManager来判断所请求的url + httpmethod 是否符合我们数据库中的配置。然而,AccessDecisionManager并没有来判定类似需求的相关Voter, 因此,我们需要自定义一个Voter的实现(默认注册的AffirmativeBased的策略是只要有Voter投出ACCESS_GRANTED票,则判定为通过,这也正符合我们的需求)。实现voter后,有一个关键参数(Collection attributes),ConfigAttribute根据不同的情况,所代表的语义不一样。我们在此也需要实现。然而,Collection attributes参数由SecurityMetadataSource获取,因此,我们还应该实现SecurityMetadataSource。众所周知,在Spring Security中,当前用户认证信息都是通过Authentication表示,因此,我们还应该让Authentication包含用户(admin)实例。Authentication同时还包含了用户的权限信息(GrantedAuthority), 因此还应该实现GrantedAuthority。

总结一下思路步骤:

1.自定义voter实现。

2.自定义ConfigAttribute实现。

3.自定义SecurityMetadataSource实现。

4.Authentication包含用户实例(这个其实不用说,大家应该都已经这么做了)。

5.自定义GrantedAuthority实现。

项目实战

1.自定义GrantedAuthority实现

UrlGrantedAuthority.java

public class UrlGrantedAuthority implements GrantedAuthority {

private final String httpMethod;

private final String url;

public UrlGrantedAuthority(String httpMethod, String url) {
this.httpMethod = httpMethod;
this.url = url;
}

@Override
public String getAuthority() {
return url;
}

public String getHttpMethod() {
return httpMethod;
}

public String getUrl() {
return url;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;

UrlGrantedAuthority target = (UrlGrantedAuthority) o;
if (httpMethod.equals(target.getHttpMethod()) && url.equals(target.getUrl())) return true;
return false;
}

@Override
public int hashCode() {
int result = httpMethod != null ? httpMethod.hashCode() : 0;
result = 31 * result + (url != null ? url.hashCode() : 0);
return result;
}
}

2.自定义认证用户实例

public class SystemUser implements UserDetails {

private final Admin admin;

private List menuOutputList;

private final List grantedAuthorities;

public SystemUser(Admin admin, List grantedPrivileges, List menuOutputList) {
this.admin = admin;
this.grantedAuthorities = grantedPrivileges.stream().map(it -> {
String method = it.getMethod() != null ? it.getMethod().getLabel() : null;
return new UrlGrantedAuthority(method, it.getUrl());
}).collect(Collectors.toList());
this.menuOutputList = menuOutputList;
}

@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return this.grantedAuthorities;
}

@Override
public String getPassword() {
return admin.getPassword();
}

@Override
public String getUsername() {
return null;
}

@Override
public boolean isAccountNonExpired() {
return true;
}

@Override
public boolean isAccountNonLocked() {
return true;
}

@Override
public boolean isCredentialsNonExpired() {
return true;
}

@Override
public boolean isEnabled() {
return true;
}

public Long getId() {
return admin.getId();
}

public Admin getAdmin() {
return admin;
}

public List getMenuOutputList() {
return menuOutputList;
}

public String getSalt() {
return admin.getSalt();
}
}

3.自定义UrlConfigAttribute实现

public class UrlConfigAttribute implements ConfigAttribute {

private final HttpServletRequest httpServletRequest;

public UrlConfigAttribute(HttpServletRequest httpServletRequest) {
this.httpServletRequest = httpServletRequest;
}

@Override
public String getAttribute() {
return null;
}

public HttpServletRequest getHttpServletRequest() {
return httpServletRequest;
}
}

4.自定义SecurityMetadataSource实现

public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

@Override
public Collection getAttributes(Object object) throws IllegalArgumentException {
final HttpServletRequest request = ((FilterInvocation) object).getRequest();
Set allAttributes = new HashSet<>();
ConfigAttribute configAttribute = new UrlConfigAttribute(request);
allAttributes.add(configAttribute);
return allAttributes;
}

@Override
public Collection getAllConfigAttributes() {
return null;
}

@Override
public boolean supports(Class<?> clazz) {
return FilterInvocation.class.isAssignableFrom(clazz);
}

}

5.自定义voter实现

public class UrlMatchVoter implements AccessDecisionVoter

posted on 2016-12-05 09:17  南轲梦  阅读(13258)  评论(3)    收藏  举报
刷新页面返回顶部
博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3