您的位置:首页 > 编程语言 > Java开发

springboot+security整合3

2018-07-23 23:23 357 查看
上一篇,springboot+security整合2,demo地址

  这篇讲解如何自定义鉴权过程,实现根据数据库查询出的url和method是否匹配当前请求的url和method来决定有没有权限。security鉴权过程如下:



一、 重写metadataSource类

编写MyGranteAuthority类,让权限包含url和method两个部分。

public class MyGrantedAuthority implements GrantedAuthority {
private String method;
private String url;

public MyGrantedAuthority(String method, String url) {
this.method = method;
this.url = url;
}

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

public String getMethod() {
return method;
}

public String getUrl() {
return url;
}

@Override
public boolean equals(Object obj) {
if(this==obj) return true;
if(obj==null||getClass()!= obj.getClass()) return false;
MyGrantedAuthority grantedAuthority = (MyGrantedAuthority)obj;
if(this.method.equals(grantedAuthority.getMethod())&&this.url.equals(grantedAuthority.getUrl()))
return true;
return false;
}
}


编写MyConfigAttribute类,实现ConfigAttribute接口,代码如下:

public class MyConfigAttribute implements ConfigAttribute {
private HttpServletRequest httpServletRequest;
private MyGrantedAuthority myGrantedAuthority;

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

public MyConfigAttribute(HttpServletRequest httpServletRequest, MyGrantedAuthority myGrantedAuthority) {
this.httpServletRequest = httpServletRequest;
this.myGrantedAuthority = myGrantedAuthority;
}

public HttpServletRequest getHttpServletRequest() {
return httpServletRequest;
}

@Override
public String getAttribute() {
return myGrantedAuthority.getUrl();
}

public MyGrantedAuthority getMyGrantedAuthority() {
return myGrantedAuthority;
}
}


编写MySecurityMetadataSource类,获取当前url所需要的权限

@Component
public class MySecurityMetadataSource implements FilterInvocationSecurityMetadataSource {

private Logger log = LoggerFactory.getLogger(this.getClass());

@Autowired
private JurisdictionMapper jurisdictionMapper;
private List<Jurisdiction> jurisdictions;

private void loadResource() {
this.jurisdictions = jurisdictionMapper.selectAllPermission();
}

@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
if (jurisdictions == null) this.loadResource();
HttpServletRequest request = ((FilterInvocation) object).getRequest();
Set<ConfigAttribute> allConfigAttribute = new HashSet<>();
AntPathRequestMatcher matcher;
for (Jurisdiction jurisdiction : jurisdictions) {
//使用AntPathRequestMatcher比较可让url支持ant风格,例如/user/*/a
//*匹配一个或多个字符,**匹配任意字符或目录
matcher = new AntPathRequestMatcher(jurisdiction.getUrl(), jurisdiction.getMethod());
if (matcher.matches(request)) {
ConfigAttribute configAttribute = new MyConfigAttribute(request,new MyGrantedAuthority(jurisdiction.getMethod(),jurisdiction.getUrl()));
allConfigAttribute.add(configAttribute);
//这里是获取到一个权限就返回,根据校验规则也可获取多个然后返回
return allConfigAttribute;
}
}
//未匹配到,说明无需权限验证
return null;
}

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

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

二、 编写MyAccessDecisionManager类

  实现AccessDecisionManager接口以实现权限判断,直接return说明验证通过,如不通过需要抛出对应错误,代码如下:

@Component
public class MyAccessDecisionManager implements AccessDecisionManager{
private Logger log = LoggerFactory.getLogger(this.getClass());

@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
//无需验证放行
if(configAttributes==null || configAttributes.size()==0)
return;
if(!authentication.isAuthenticated()){
throw new InsufficientAuthenticationException("未登录");
}
Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities();
for(ConfigAttribute attribute : configAttributes){
MyConfigAttribute urlConfigAttribute = (MyConfigAttribute)attribute;
for(GrantedAuthority authority: authorities){
MyGrantedAuthority myGrantedAuthority = (MyGrantedAuthority)authority;
if(urlConfigAttribute.getMyGrantedAuthority().equals(myGrantedAuthority))
return;
}
}
throw new AccessDeniedException("无权限");
}

@Override
public boolean supports(ConfigAttribute attribute) {
return true;
}

@Override
public boolean supports(Class<?> clazz) {
return true;
}
}

三、 编写MyFilterSecurityInterceptor类

  该类继承AbstractSecurityInterceptor类,实现Filter接口,代码如下:

@Component
public class MyFilterSecurityInterceptor extends AbstractSecurityInterceptor implements Filter {

//注入上面编写的两个类
@Autowired
private MySecurityMetadataSource mySecurityMetadataSource;

@Autowired
public void setMyAccessDecisionManager(MyAccessDecisionManager myAccessDecisionManager) {
super.setAccessDecisionManager(myAccessDecisionManager);
}

@Override
public void init(FilterConfig arg0) throws ServletException {
}

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}

public void invoke(FilterInvocation fi) throws IOException, ServletException {
//这里进行权限验证
InterceptorStatusToken token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}

@Override
public void destroy() {
}

@Override
public Class<?> getSecureObjectClass() {
return FilterInvocation.class;
}

@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.mySecurityMetadataSource;
}
}

四、 加入到security的过滤器链中

.addFilterBefore(urlFilterSecurityInterceptor,FilterSecurityInterceptor.class)

完成
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: