In diesem Artikel wird hauptsächlich das benutzerdefinierte Beispiel für die Spring Security-Berechtigungssteuerung in Java vorgestellt (praktischer Artikel). Interessierte Freunde können darauf verweisen.
Hintergrundbeschreibung
Das Projekt muss eine feinkörnige Berechtigungskontrolle durchführen, die so detailliert ist wie URL + http-Methode (zufrieden stellen, zum Beispiel: http://www. php.cn /, einige Rollen können nur anzeigen (HTTP GET), haben aber keine Berechtigung zum Hinzufügen, Ändern oder Löschen (POST, PUT, DELETE)).
Tabellendesign
Um Verdacht zu vermeiden, werden nur die zu verwendenden Schlüsselfelder aufgeführt, den Rest finden Sie bitte selbst heraus.
1.admin_user Administrator-Benutzertabelle, Schlüsselfelder (id, role_id).
2.t_role Rollentabelle, Schlüsselfelder (ID, Privilege_ID).
3.t_privilege-Berechtigungstabelle, Schlüsselfelder (ID, URL, Methode)
Unnötig mehr über die Beziehung zwischen den drei Tabellen zu sagen, Sie können sie auf einen Blick sehen die Felder raus.
Analyse vor der Implementierung
Wir können umgekehrt denken:
Um unsere Bedürfnisse zu erkennen, besteht der wichtigste Schritt darin, den AccessDecisionManager von Spring Security beurteilen zu lassen Ob die angeforderte URL + http-Methode mit der Konfiguration in unserer Datenbank übereinstimmt. AccessDecisionManager ermittelt jedoch keine verwandten Wähler mit ähnlichen Anforderungen. Daher müssen wir eine Wählerimplementierung anpassen (die standardmäßig registrierte AffirmativeBased-Strategie sieht vor, dass, solange ein Wähler eine ACCESS_GRANTED-Stimme abgibt, diese als bestanden gilt, was im Einklang steht mit unserem Bedürfnis). Nach der Implementierung des Voters gibt es einen Schlüsselparameter (Collection
Um die Denkschritte zusammenzufassen:
1. Passen Sie die Voter-Implementierung an.
2. Passen Sie die ConfigAttribute-Implementierung an.
3. Passen Sie die SecurityMetadataSource-Implementierung an.
4. Passen Sie die GrantedAuthority-Implementierung an.
Projekt tatsächlicher Kampf1. Angepasste GrantedAuthority-Implementierung
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. Benutzerdefinierte Authentifizierungsbenutzerinstanz
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. Angepasste URLConfigAttribute-Implementierung
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. Benutzerdefinierte SecurityMetadataSource-Implementierung
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. Angepasst Wähler-Implementierung
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; //如果数据库的method字段为null,则默认为所有方法都支持 String httpMethod = StringUtils.isNotBlank(urlGrantedAuthority.getHttpMethod()) ? urlGrantedAuthority.getHttpMethod() : urlConfigAttribute.getHttpServletRequest().getMethod(); //用Spring已经实现的AntPathRequestMatcher进行匹配,这样我们数据库中的url也就支持ant风格的配置了(例如:/xxx/user/**) AntPathRequestMatcher antPathRequestMatcher = new AntPathRequestMatcher(urlGrantedAuthority.getAuthority(), httpMethod); if (antPathRequestMatcher.matches(urlConfigAttribute.getHttpServletRequest())) return ACCESS_GRANTED; } } return ACCESS_ABSTAIN; } }
6. Angepasste FilterSecurityInterceptor-Implementierung
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); } }
Konfigurationsdateischlüsselkonfiguration
<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>
Okay, jetzt genießen Sie Ihre Spring Security-Berechtigungskontrolle. Machen wir uns auf die Reise
Das Obige ist der Inhalt des benutzerdefinierten Beispiels für die Berechtigungssteuerung von Spring Security in Java (praktischer Artikel). Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website (www.php.cn)! >