今天就跟大家聊聊有關(guān)java中如何實現(xiàn)自定義Spring Security權(quán)限,可能很多人都不太了解,為了讓大家更加了解,小編給大家總結(jié)了以下內(nèi)容,希望大家根據(jù)這篇文章可以有所收獲。
成都創(chuàng)新互聯(lián)公司專業(yè)為企業(yè)提供永濟(jì)網(wǎng)站建設(shè)、永濟(jì)做網(wǎng)站、永濟(jì)網(wǎng)站設(shè)計、永濟(jì)網(wǎng)站制作等企業(yè)網(wǎng)站建設(shè)、網(wǎng)頁設(shè)計與制作、永濟(jì)企業(yè)網(wǎng)站模板建站服務(wù),10余年永濟(jì)做網(wǎng)站經(jīng)驗,不只是建網(wǎng)站,更提供有價值的思路和整體網(wǎng)絡(luò)服務(wù)。
背景描述
項目中需要做細(xì)粒的權(quán)限控制,細(xì)微至url + httpmethod (滿足restful,例如: https://.../xxx/users/1, 某些角色只能查看(HTTP GET), 而無權(quán)進(jìn)行增改刪(POST, PUT, DELETE))。
表設(shè)計
為避嫌,只列出要用到的關(guān)鍵字段,其余敬請自行腦補。
1.admin_user 管理員用戶表, 關(guān)鍵字段( id, role_id )。
2.t_role 角色表, 關(guān)鍵字段( id, privilege_id )。
3.t_privilege 權(quán)限表, 關(guān)鍵字段( id, url, method )
三個表的關(guān)聯(lián)關(guān)系就不用多說了吧,看字段一眼就能看出。
實現(xiàn)前分析
我們可以逆向思考:
要實現(xiàn)我們的需求,最關(guān)鍵的一步就是讓Spring Security的AccessDecisionManager來判斷所請求的url + httpmethod 是否符合我們數(shù)據(jù)庫中的配置。然而,AccessDecisionManager并沒有來判定類似需求的相關(guān)Voter, 因此,我們需要自定義一個Voter的實現(xiàn)(默認(rèn)注冊的AffirmativeBased的策略是只要有Voter投出ACCESS_GRANTED票,則判定為通過,這也正符合我們的需求)。實現(xiàn)voter后,有一個關(guān)鍵參數(shù)(Collection
總結(jié)一下思路步驟:
1.自定義voter實現(xiàn)。
2.自定義ConfigAttribute實現(xiàn)。
3.自定義SecurityMetadataSource實現(xiàn)。
4.Authentication包含用戶實例(這個其實不用說,大家應(yīng)該都已經(jīng)這么做了)。
5.自定義GrantedAuthority實現(xiàn)。
項目實戰(zhàn)
1.自定義GrantedAuthority實現(xiàn)
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.自定義認(rèn)證用戶實例
public class SystemUser implements UserDetails { private final Admin admin; private List<MenuOutput> menuOutputList; private final List<GrantedAuthority> grantedAuthorities; public SystemUser(Admin admin, List<AdminPrivilege> grantedPrivileges, List<MenuOutput> 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<MenuOutput> getMenuOutputList() { return menuOutputList; } public String getSalt() { return admin.getSalt(); } }
3.自定義UrlConfigAttribute實現(xiàn)
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實現(xiàn)
public class UrlFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Override public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException { final HttpServletRequest request = ((FilterInvocation) object).getRequest(); Set<ConfigAttribute> allAttributes = new HashSet<>(); ConfigAttribute configAttribute = new UrlConfigAttribute(request); allAttributes.add(configAttribute); return allAttributes; } @Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; } @Override public boolean supports(Class<?> clazz) { return FilterInvocation.class.isAssignableFrom(clazz); } }
5.自定義voter實現(xiàn)
public class UrlMatchVoter implements AccessDecisionVoter<Object> { @Override public boolean supports(ConfigAttribute attribute) { if (attribute instanceof UrlConfigAttribute) return true; return false; } @Override public boolean supports(Class<?> clazz) { return true; } @Override public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { if(authentication == null) { return ACCESS_DENIED; } Collection<? extends GrantedAuthority> authorities = authentication.getAuthorities(); for (ConfigAttribute attribute : attributes) { if (!(attribute instanceof UrlConfigAttribute)) continue; UrlConfigAttribute urlConfigAttribute = (UrlConfigAttribute) attribute; for (GrantedAuthority authority : authorities) { if (!(authority instanceof UrlGrantedAuthority)) continue; UrlGrantedAuthority urlGrantedAuthority = (UrlGrantedAuthority) authority; if (StringUtils.isBlank(urlGrantedAuthority.getAuthority())) continue; //如果數(shù)據(jù)庫的method字段為null,則默認(rèn)為所有方法都支持 String httpMethod = StringUtils.isNotBlank(urlGrantedAuthority.getHttpMethod()) ? urlGrantedAuthority.getHttpMethod() : urlConfigAttribute.getHttpServletRequest().getMethod(); //用Spring已經(jīng)實現(xiàn)的AntPathRequestMatcher進(jìn)行匹配,這樣我們數(shù)據(jù)庫中的url也就支持ant風(fēng)格的配置了(例如:/xxx/user/**) AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(urlGrantedAuthority.getAuthority(), httpMethod); if (antPathRequestMatcher.matches(urlConfigAttribute.getHttpServletRequest())) return ACCESS_GRANTED; } } return ACCESS_ABSTAIN; } }
6.自定義FilterSecurityInterceptor實現(xiàn)
public class UrlFilterSecurityInterceptor extends FilterSecurityInterceptor { public UrlFilterSecurityInterceptor() { super(); } @Override public void init(FilterConfig arg0) throws ServletException { super.init(arg0); } @Override public void destroy() { super.destroy(); } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { super.doFilter(request, response, chain); } @Override public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() { return super.getSecurityMetadataSource(); } @Override public SecurityMetadataSource obtainSecurityMetadataSource() { return super.obtainSecurityMetadataSource(); } @Override public void setSecurityMetadataSource(FilterInvocationSecurityMetadataSource newSource) { super.setSecurityMetadataSource(newSource); } @Override public Class<?> getSecureObjectClass() { return super.getSecureObjectClass(); } @Override public void invoke(FilterInvocation fi) throws IOException, ServletException { super.invoke(fi); } @Override public boolean isObserveOncePerRequest() { return super.isObserveOncePerRequest(); } @Override public void setObserveOncePerRequest(boolean observeOncePerRequest) { super.setObserveOncePerRequest(observeOncePerRequest); } }
配置文件關(guān)鍵配置
<security:http> ... <security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR" /> </security:http> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="daoAuthenticationProvider"/> </security:authentication-manager> <bean id="accessDecisionManager" class="org.springframework.security.access.vote.AffirmativeBased"> <constructor-arg> <list> <bean id="authenticatedVoter" class="org.springframework.security.access.vote.AuthenticatedVoter" /> <bean id="roleVoter" class="org.springframework.security.access.vote.RoleVoter" /> <bean id="urlMatchVoter" class="com.mobisist.app.security.access.voter.UrlMatchVoter" /> </list> </constructor-arg> </bean> <bean id="securityMetadataSource" class="com.mobisist.app.security.access.UrlFilterInvocationSecurityMetadataSource" /> <bean id="filterSecurityInterceptor" class="com.mobisist.app.security.access.UrlFilterSecurityInterceptor"> <property name="authenticationManager" ref="authenticationManager"/> <property name="accessDecisionManager" ref="accessDecisionManager"/> <property name="securityMetadataSource" ref="securityMetadataSource" /> </bean>
看完上述內(nèi)容,你們對java中如何實現(xiàn)自定義Spring Security權(quán)限有進(jìn)一步的了解嗎?如果還想了解更多知識或者相關(guān)內(nèi)容,請關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道,感謝大家的支持。
當(dāng)前題目:java中如何實現(xiàn)自定義SpringSecurity權(quán)限
標(biāo)題路徑:http://www.ekvhdxd.cn/article4/pooioe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供微信小程序、網(wǎng)站設(shè)計公司、網(wǎng)站內(nèi)鏈、企業(yè)網(wǎng)站制作、響應(yīng)式網(wǎng)站、虛擬主機
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)