完整代碼見附件
目錄
1. 需要在spring-security.xml中配置驗證過濾器,來取代spring-security.xml的默認過濾器
spring-security中需要配置驗證過濾器來實現整個攔截的過程,其中需要配置一下三個來實現。
authenticationManager:在配置用戶名和角色的時候,已經配置過了。 security:authentication-manager
accessDecisionManager:用來判斷url是否有權限
securityMetadataSource:可以通過url得到角色名稱
<!-- 配置 驗證過濾器, 此過濾器取代系統的XML權限過濾 , 此過濾器配置完畢之后存放到 系統缺省的過濾鏈中-->
<bean id="filterSecurityInterceptor" class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">
<!-- 需要認證管理器, 通過它可以獲取 管理員已經擁有的角色信息 ,
由於id已經被org.springframework.security.authenticationManager默認了。不能更改,所以用別名-->
<property name="authenticationManager" ref="authenticationManager"></property>
<!-- 決策器 -->
<property name="accessDecisionManager" ref="roleAccessDecisionManager" />
<!-- 配置urlService ,security可以通過url得到角色名稱 -->
<property name="securityMetadataSource" ref="urlService" />
</bean>
2. 配置securityMetadataSource,可以通過url來獲取角色名稱
package com.hp.service.impl;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.annotation.Resource;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import org.springframework.stereotype.Service;
import com.hp.dao.UrlDao;
import com.hp.model.Role;
import com.hp.model.Url;
import com.hp.service.UrlService;
/**
* 通過URL地址獲取相應權限然后在獲取相應的角色集合
*
* 需要實現FilterInvocationSecurityMetadataSource接口
*
* @author baojulin
*
*/
@Service("urlService")
public class UrlServiceImpl implements UrlService, FilterInvocationSecurityMetadataSource {
@Resource
private UrlDao urlDao;
@Override
public Url getRoleByUrl(String url) {
return urlDao.getRoleByUrl(url);
}
/**
* 此方法就是通過url地址獲取 角色信息的方法
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
// 獲取當前的URL地址
System.out.println("object的類型為:" + object.getClass());
FilterInvocation filterInvocation = (FilterInvocation) object;
String url = filterInvocation.getRequestUrl();
System.out.println("訪問的URL地址為(包括參數):" + url);
url = filterInvocation.getRequest().getServletPath();
System.out.println("訪問的URL地址為:" + url);
Url urlObject = getRoleByUrl(url); //調用自己實現的方法來url
System.out.println("urlObject:" + urlObject);
if (urlObject != null && urlObject.getPrivilege() != null) {
Set<Role> roles = urlObject.getPrivilege().getRoles();
Collection<ConfigAttribute> c = new HashSet<ConfigAttribute>();
c.addAll(roles);
return c; // 將privilege中的roles改為Collection<ConfigAttribute>,role需要實現ConfigAttribute接口
} else {
// 如果返回為null則說明此url地址不需要相應的角色就可以訪問, 這樣Security會放行
return null;
}
}
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
/**
* 如果為真則說明支持當前格式類型,才會到上面的 getAttributes 方法中
*/
@Override
public boolean supports(Class<?> clazz) {
// TODO Auto-generated method stub
// 需要返回true表示支持
return true;
}
}
urlDao中的實現
/**
* 通過URL地址獲取相應權限然后在獲取相應的角色集合
*/
@Override
public Url getRoleByUrl(String url) {
String hql = "FROM Url u JOIN FETCH u.privilege up JOIN FETCH up.roles WHERE u.url=:url";
Session session = sessionFactory.openSession();
return (Url) session.createQuery(hql).setString("url", url).uniqueResult();
}
3. 配置決策器:roleAccessDecisionManager
package com.hp.service.impl;
import java.util.Collection;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.security.access.AccessDecisionManager;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
/**
* 此類是決策器: 用來對 用戶應有的角色,與URL地址可以訪問的角色進行對比,如果不匹配則拋出異常
*
* @author baojulin
*
*/
@Service("roleAccessDecisionManager")
public class RoleAccessDecisionManager implements AccessDecisionManager {
protected final Log logger = LogFactory.getLog(RoleAccessDecisionManager.class);
/**
* 決策方法: 如果方法執行完畢沒有拋出異常,則說明可以放行, 否則拋出異常 AccessDeniedException
*/
@Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException {
// System.out.println("---------------decide------------------");
// 如果登陸成功,則信息會存儲在Authorities中
Collection<? extends GrantedAuthority> myRoles = authentication.getAuthorities();
// 如果前面的 getAttributes() 返回非空,則返回的數據做為形參傳入, 如果返回為null 則不會進入decide() 直接放行
// System.out.println("myRole:" + myRoles);
// System.out.println("sysRole:" + configAttributes);
for (GrantedAuthority myRole : myRoles) {// 當前登錄的角色
for (ConfigAttribute urlRoles : configAttributes) {// 前台傳入的url的角色,UrlDaoImpl.getAttributes獲得的
if (myRole.getAuthority().equals(urlRoles.getAttribute())) {
// 說明此URL地址符合權限,可以放行
return;
}
}
}
// System.out.println("-----權限驗證失敗------");
logger.error("-----權限驗證失敗------");
throw new AccessDeniedException("權限越界!");
}
/**
* 返回true表示支持
*/
@Override
public boolean supports(ConfigAttribute attribute) {
// System.out.println("public boolean supports(ConfigAttribute attribute)");
return true;
}
/**
* 返回true表示支持
*/
@Override
public boolean supports(Class<?> clazz) {
// System.out.println("public boolean supports(Class<?> clazz)");
return true;
}
}
4. 在配置文件中,修改默認過濾器,將xml方式配置的權限去掉,改用數據庫
<security:http auto-config="false" use-expressions="true" access-denied-page="/login.jsp?error=access-denied-page">
<!-- xml配置,配置的 pattern="/admin/**" 表示需要登錄才能訪問,而登錄的角色為ROLE_ADMIN
<security:intercept-url pattern="/admin/**" access="hasRole('ROLE_ADMIN')" />
<security:intercept-url pattern="/user/**" access="hasAnyRole('ROLE_USER','ROLE_ADMIN')" />
-->
<!-- 增加權限過濾器,采用數據庫方式獲取權限 -->
<security:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>
<!-- 默認登錄地址:j_spring_security_check -->
<security:form-login default-target-url="/index.jsp"
username-parameter="username"
password-parameter="password"
authentication-failure-url="/login.jsp?error=authentication-failure-url"
login-page="/login.jsp"/>
<!-- 注銷也是由,Security框架來實現,LogoutFilter ,默認地址j_spring_security_logout -->
<security:logout logout-success-url="/login.jsp"/>
</security:http>
5. 圖解spring-security整個流程
百度雲鏈接:http://pan.baidu.com/s/1cBTdb4 密碼:pjzk