235 lines
20 KiB
Markdown
235 lines
20 KiB
Markdown
|
  这篇讲解如何自定义鉴权过程,实现根据数据库查询出的url和method是否匹配当前请求的url和method来决定有没有权限。security鉴权过程如下:
|
|||
|
![鉴权流程][鉴权流程]
|
|||
|
|
|||
|
##一、 重写metadataSource类
|
|||
|
|
|||
|
1. 编写MyGranteAuthority类,让权限包含url和method两个部分。
|
|||
|
```java
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
2. 编写MyConfigAttribute类,实现ConfigAttribute接口,代码如下:
|
|||
|
```java
|
|||
|
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;
|
|||
|
}
|
|||
|
}
|
|||
|
```
|
|||
|
3. 编写MySecurityMetadataSource类,获取当前url所需要的权限
|
|||
|
```java
|
|||
|
@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说明验证通过,如不通过需要抛出对应错误,代码如下:
|
|||
|
```java
|
|||
|
@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接口,代码如下:
|
|||
|
```java
|
|||
|
@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的过滤器链中
|
|||
|
```java
|
|||
|
.addFilterBefore(urlFilterSecurityInterceptor,FilterSecurityInterceptor.class)
|
|||
|
```
|
|||
|
完成
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
[鉴权流程]:data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAQAAD/4QOTaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjMtYzAxMSA2Ni4xNDU2NjEsIDIwMTIvMDIvMDYtMTQ6NTY6MjcgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6RTk3RUIwQzU4RTQwMTFFODk1NkNFMDY2NjI4REM4NjAiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6RTk3RUIwQzQ4RTQwMTFFODk1NkNFMDY2NjI4REM4NjAiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENTNiBXaW5kb3dzIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InV1aWQ6ZmFmNWJkZDUtYmEzZC0xMWRhLWFkMzEtZDMzZDc1MTgyZjFiIiBzdFJlZjpkb2N1bWVudElEPSIxOEQzQTk4QkIxMTFERTA1MjY5MkYxNzEyNTZEMzJEMSIvPiA8ZGM6Y3JlYXRvcj4gPHJkZjpTZXE+IDxyZGY6bGk+ZnhiPC9yZGY6bGk+IDwvcmRmOlNlcT4gPC9kYzpjcmVhdG9y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
|