spring security2中实现数据库管理认证和授权,版本号是spring security2.0.4,为简述方便,本文只列举关键代码。
认证:
其中userDetailsService类的实现:
obtainGrantedAuthorities类的实现:
第一种,GrantedAuthority中存放的是role表中的name。
第二种,GrantedAuthority中存放的是reresource表中的name。
授权:
有2种实现,一是新写了一个FactoryBean,向默认的DefaultFilterInvocationDefinitionSource注入从ResourceDetailService中返回的RequestMap。
DefinitionSourceFactoryBean中代码:
ResourceDetailsServiceImpl中getRequestMap()代码,对应认证中GrantedAuthority中存放的是role表中的name而言,此处resourceMap中也就应该放置资源对应的role表的name:
第2中授权的实现,重写FilterInvocationDefinitionSource类。
对应认证中的第二种实现(GrantedAuthority中存放的是reresource表中的name),GrantedAuthority[]变量authorities实质上是单条url资源对应的name。
2种授权的实现,我分别列举了ss3ex和ss3中的实现,lingo文档中的实现基本类似于ss3,综上所述,授权时有新写一个FactoryBean和重写FilterInvocationDefinitionSource类2种实现,每种实现中又分别有对应2种不同的认证,所以个共有4种实现方案,本文列举了其中2种,另2种省略。
1、那么GrantedAuthority中到底应该放什么呢?
回答:这个没有要求,只要保证认证和授权时保持一致就行了。
2、ss3ex中资源是置入缓存中的,用户访问URL时,针对每个URL与缓存中的权限进行比较,而ss3中的(资源-角色[])是系统初始化时一次性读取放入内存中,待用户访问URL时分别与内存中的比较。两者的性能方面,差不多。
3、哪种在实际工作中适用些呢?
回答:如果你的URL是以“?”带有参数的话,2者都可以使用,ss3ex中需要写个缓存。如果你的URL中的规则不是“?”带有参数的,那么只要稍微修改下ss3ex中的实现方式了,即重写FilterInvocationDefinitionSource类的实现;而ss3中的做法是调用默认的FilterInvocationDefinitionSource实现DefaultFilterInvocationDefinitionSource类的构造函数,但是FilterInvocationDefinitionSource的默认实现类中的getAttributes方法又调用类中的lookupAttributes方法的实现,在lookupAttributes方法中是写死为截掉“?”参数的,这时如果要用这个DefaultFilterInvocationDefinitionSource类的话,还要想办法重写它里面的lookupAttributes方法。
4、修改资源时,ss3ex中是必须要重新设置缓存的,而lingo对于他的实现中是重新设置下内存。
认证:
<authentication-provider user-service-ref="userDetailsService">
<password-encoder hash="md5">
<salt-source user-property="username" />
</password-encoder>
</authentication-provider>
其中userDetailsService类的实现:
public UserDetails loadUserByUsername(String userName)
throws UsernameNotFoundException, DataAccessException {
User user = securityManager.findUserByLoginName(userName);
if (user == null)
throw new UsernameNotFoundException("用户" + userName + " 不存在");
GrantedAuthority[] grantedAuths = obtainGrantedAuthorities(user);
// san中无以下属性,暂时全部设为true.
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
org.springframework.security.userdetails.User userdetail = new
org.springframework.security.userdetails.User(
user.getLoginName(), user.getPassword(), enabled,
accountNonExpired, credentialsNonExpired, accountNonLocked,
grantedAuths);
return userdetail;
}
obtainGrantedAuthorities类的实现:
第一种,GrantedAuthority中存放的是role表中的name。
/**
* 获得用户所有角色的权限集合.
*/
private GrantedAuthority[] obtainGrantedAuthorities(User user) {
List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority>();
GrantedAuthority ag=null;
List<Role> roleList=userService.getRoleByLoginName(userName);
for (Role role : roleList) {
ag=new GrantedAuthorityImpl(role.getName());
authsList.add(ag);
ag=null;
}
return authSet.toArray(new GrantedAuthority[authsList.size()]);
}
第二种,GrantedAuthority中存放的是reresource表中的name。
/**
* 获得用户所有角色的权限集合.
*/
private GrantedAuthority[] obtainGrantedAuthorities(User user) {
List<GrantedAuthority> authsList = new ArrayList<GrantedAuthority>();
GrantedAuthority ag=null;
for (Role role : user.getRoles()) {
for(Resource res:role.getResources()){
ag=new GrantedAuthorityImpl(res.getName());
authsList.add(ag);
ag=null;
}
}
return authSet.toArray(new GrantedAuthority[authsList.size()]);
}
授权:
有2种实现,一是新写了一个FactoryBean,向默认的DefaultFilterInvocationDefinitionSource注入从ResourceDetailService中返回的RequestMap。
<beans:bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" />
<beans:property name="authenticationManager" ref="authenticationManager" />
<beans:property name="accessDecisionManager" ref="accessDecisionManager" />
<beans:property name="objectDefinitionSource" ref="databaseDefinitionSource" />
</beans:bean>
<!-- DefinitionSource工厂,使用resourceDetailsService提供的URL-授权关系. -->
<beans:bean id="databaseDefinitionSource"
class="san.service.Impl.DefinitionSourceFactoryBean">
<beans:property name="resourceDetailsService" ref="resourceDetailsService" />
</beans:bean>
<!-- 项目实现的URL-授权查询服务 -->
<beans:bean id="resourceDetailsService" class="san.service.Impl.ResourceDetailsServiceImpl" />
DefinitionSourceFactoryBean中代码:
public class DefinitionSourceFactoryBean implements FactoryBean {
public Object getObject() throws Exception {
LinkedHashMap<RequestKey, ConfigAttributeDefinition> requestMap = getRequestMap();
UrlMatcher matcher = getUrlMatcher();
DefaultFilterInvocationDefinitionSource definitionSource = new DefaultFilterInvocationDefinitionSource(
matcher, requestMap);
return definitionSource;
}
private LinkedHashMap<RequestKey, ConfigAttributeDefinition> getRequestMap()
throws Exception {
LinkedHashMap<String, String> srcMap = resourceDetailsService
.getRequestMap();
LinkedHashMap<RequestKey, ConfigAttributeDefinition> requestMap = new LinkedHashMap<RequestKey,ConfigAttributeDefinition>();
ConfigAttributeEditor editor = new ConfigAttributeEditor();
for (Entry<String, String> entry : srcMap.entrySet()) {
RequestKey key = new RequestKey(entry.getKey(), null);
editor.setAsText(entry.getValue());
requestMap.put(key, (ConfigAttributeDefinition) editor.getValue());
}
return requestMap;
}
}
ResourceDetailsServiceImpl中getRequestMap()代码,对应认证中GrantedAuthority中存放的是role表中的name而言,此处resourceMap中也就应该放置资源对应的role表的name:
public LinkedHashMap<String, String> getRequestMap() throws Exception {
List<Map> roleList = userDAO.getRoleByResource("");
LinkedHashMap<String, String> resourceMap = new LinkedHashMap<String, String>();
for (Map o : roleList) {
String url = o.get("path").toString();
String role = o.get("role").toString();
if (resourceMap.containsKey(url)) {
String value = resourceMap.get(url);
resourceMap.put(url, value + "," + role);
} else {
resourceMap.put(url, role);
}
}
return resourceMap;
}
第2中授权的实现,重写FilterInvocationDefinitionSource类。
对应认证中的第二种实现(GrantedAuthority中存放的是reresource表中的name),GrantedAuthority[]变量authorities实质上是单条url资源对应的name。
public class DbFilterInvocationDefinitionSource implements
FilterInvocationDefinitionSource, InitializingBean {
……
public ConfigAttributeDefinition getAttributes(Object filter)
throws IllegalArgumentException {
GrantedAuthority[] authorities = new GrantedAuthority[0];
Resource resource = null;
Collection resources = SecurityResourceCache.getAllCache();
for (Iterator it = resources.iterator(); it.hasNext();) {
resource = (Resource) it.next();
String resPath = resource.getPath();
boolean matched = urlMatcher.pathMatchesUrl(resPath, requestURI);
if (matched) {
authorities = SecurityResourceCache.getAuthoritysInCache(resPath);
break;
}
}
if (authorities != null && authorities.length > 0) {
String authoritiesStr = " ";
for (int i = 0; i < authorities.length; i++) {
authoritiesStr += authorities[i].getAuthority() + ",";
}
String authStr = authoritiesStr.substring(0, authoritiesStr
.length() - 1);
ConfigAttributeEditor configAttrEditor = new ConfigAttributeEditor();
configAttrEditor.setAsText(authStr.trim());
return (ConfigAttributeDefinition) configAttrEditor.getValue();
}
return null;
}
}
2种授权的实现,我分别列举了ss3ex和ss3中的实现,lingo文档中的实现基本类似于ss3,综上所述,授权时有新写一个FactoryBean和重写FilterInvocationDefinitionSource类2种实现,每种实现中又分别有对应2种不同的认证,所以个共有4种实现方案,本文列举了其中2种,另2种省略。
1、那么GrantedAuthority中到底应该放什么呢?
回答:这个没有要求,只要保证认证和授权时保持一致就行了。
2、ss3ex中资源是置入缓存中的,用户访问URL时,针对每个URL与缓存中的权限进行比较,而ss3中的(资源-角色[])是系统初始化时一次性读取放入内存中,待用户访问URL时分别与内存中的比较。两者的性能方面,差不多。
3、哪种在实际工作中适用些呢?
回答:如果你的URL是以“?”带有参数的话,2者都可以使用,ss3ex中需要写个缓存。如果你的URL中的规则不是“?”带有参数的,那么只要稍微修改下ss3ex中的实现方式了,即重写FilterInvocationDefinitionSource类的实现;而ss3中的做法是调用默认的FilterInvocationDefinitionSource实现DefaultFilterInvocationDefinitionSource类的构造函数,但是FilterInvocationDefinitionSource的默认实现类中的getAttributes方法又调用类中的lookupAttributes方法的实现,在lookupAttributes方法中是写死为截掉“?”参数的,这时如果要用这个DefaultFilterInvocationDefinitionSource类的话,还要想办法重写它里面的lookupAttributes方法。
4、修改资源时,ss3ex中是必须要重新设置缓存的,而lingo对于他的实现中是重新设置下内存。