`
huttoncs
  • 浏览: 198977 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

spring security2配置

阅读更多
下面的内容也是在网上查找的资料基础上增加了一下修改,这里也省去了ssh整合的配置,只是针对spring security 2的相关内容

1、首先在web.xml中进行配置
<!-- spring security configuration 这个Filter会拦截所有的URL请求,并且对这些URL请求进行Spring Security的验证 -->
<filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

和普通的filter配置一样,非常方便

2、spring-security.xml的配置内容如下:
<b:beans xmlns="http://www.springframework.org/schema/security" xmlns:b="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
                        http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-2.0.1.xsd">
                       
<b:description>spring security configuration</b:description>
<!-- Spring Security采用就近原则,有多个约束时,从上至下只要找到第一条满足就返回,因此应该将最严格的约束放在最前面,
而将最宽松的约束放在最后面.auto-config属性可以让spring security为我们自动配置几种常用的权限控制机制,
包括form,anonymous, rememberMe等。当然你也可以手工配置。--> 
<http access-denied-page="/access-denied.jsp">
<!-- 我们利用intercept-url来判断用户需要具有何种权限才能访问对应的url资源,可以在pattern中指定一个特定的url资源,
  也可以使用通配符指定一组类似的url资源。例子中定义的两个intercepter-url,第一个用来控制对/security/**的访问,
  第二个使用了通配符/**,说明它将控制对系统中所有url资源的访问。 --> 
<intercept-url pattern="/login.jsp" filters="none" />
<intercept-url pattern="/b.jsp" access="ROLE_ADMIN" />
<intercept-url pattern="/d.jsp" filters="none" />
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp" always-use-default-target="true" default-target-url="/b.jsp"/>
<logout logout-success-url="/login.jsp"/>
</http>

<!--  验证数据提供器 -->
<authentication-provider user-service-ref='userDetailsService' >
<!-- 将 userDetailsService 的属性username用md5加密
<password-encoder hash="md5">
<salt-source user-property="username"/>
</password-encoder> 
-->
</authentication-provider>

<!-- 鉴权过滤器(URL资源拦截器) -->
<b:bean id="filterSecurityInterceptor" class="org.springframework.security.intercept.web.FilterSecurityInterceptor">
<custom-filter before="FILTER_SECURITY_INTERCEPTOR" /><!-- 指定过滤器应该出现的位置和顺序 -->
<b:property name="authenticationManager" ref="authenticationManager" />
<b:property name="accessDecisionManager" ref="accessDecisionManager" />
<b:property name="objectDefinitionSource" ref="filterInvocationDefinitionSource" />
</b:bean>

<!-- 用户-权限认证管理器 -->
<b:bean id="authenticationManager" class="org.springframework.security.providers.ProviderManager">
<b:property name="providers">
<b:list>
<b:ref local="daoAuthenticationProvider" />
</b:list>
</b:property>
</b:bean>

<!-- 决策管理器(授权器) -->
<b:bean id="accessDecisionManager" class="org.springframework.security.vote.AffirmativeBased">
<b:property name="decisionVoters">
<b:list>
<b:bean class="org.springframework.security.vote.RoleVoter">
<b:property name="rolePrefix" value="" />
</b:bean>
</b:list>
</b:property>
</b:bean>

<!-- 用户认证服务 -->
<b:bean id="daoAuthenticationProvider" class="org.springframework.security.providers.dao.DaoAuthenticationProvider">
<b:property name="userDetailsService" ref="userDetailsService" />
<b:property name="hideUserNotFoundExceptions" value="false" />
</b:bean>

     <!-- 用户信息服务接口 -->
<b:bean id="userDetailsService" class="com.xxx.eb.security.UserDetailsServiceImpl">
<b:property name="dataSource" ref="dataSource" />
<b:property name="usersByUsernameQuery">
<b:value><![CDATA[
select u.id,
       u.username,
       u.password,
       u.enable as enabled
  from
  users u
where u.username = ?
]]></b:value>
</b:property>
<b:property name="authoritiesByUsernameQuery">
<b:value><![CDATA[
select
u.username, r.name as authority
from
users u
join users_roles ur
on u.id = ur.uid
join roles r
on r.id = ur.rid
where
u.username = ?
]]>
</b:value>
</b:property>
</b:bean>

<!-- filter Invocation DefinitionSource  -->
<b:bean id="filterInvocationDefinitionSource" class="com.xxx.eb.security.JdbcFilterInvocationDefinitionSourceFactoryBean">
<b:property name="dataSource" ref="dataSource" />
<b:property name="resourceQuery">
<b:value>
<![CDATA[
select
re.url,r.name
         from
         roles r
            join roles_resources rr
                on r.id=rr.rid
            join resources re
                on re.id=rr.rsid
]]>
</b:value>
</b:property>
</b:bean>
</b:beans>                       

这里我并没有直接采用hibernate的持久化对象,而是使用的JDBC,个人觉得这样更方便,毕竟登录账户数据不会在前台就行操作

3、我把要用用到的实体类及数据库中创建的sql都放在了附件中,都比较简单,这里就不贴出来的了

4、下面是配置文件中要用到的service,各个类的作用在上面的配置文件中都有描述,这里就不再赘述

a、用户登录权限校验类
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.GrantedAuthority;
import org.springframework.security.GrantedAuthorityImpl;
import org.springframework.security.userdetails.UserDetailsService;
import org.springframework.security.userdetails.UsernameNotFoundException;

public class UserDetailsServiceImpl extends JdbcDaoSupport implements UserDetailsService {
private String usersByUsernameQuery;
private String authoritiesByUsernameQuery;

/**
* 用户查询服务
*/
@SuppressWarnings("unchecked")
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
List<Map<String, Object>> result = super.getJdbcTemplate().queryForList(usersByUsernameQuery, new Object[] { username });
if (result.size() == 1) {
Map<String, Object> row = result.get(0);
row.put(UserDetails.AUTHORITIES, obtainGrantedAuthorities(username));
UserDetails user = new UserDetails();
user.getUserInfo().putAll(row);
return user;
}
throw new UsernameNotFoundException("登陆的账号[" + username + "] 无效!");
}

/**
* 查询用户的角色
*/
@SuppressWarnings("unchecked")
private GrantedAuthority[] obtainGrantedAuthorities(String username) {
List<Map<String, Object>> result = super.getJdbcTemplate().queryForList(this.authoritiesByUsernameQuery, new Object[] { username });
List<GrantedAuthority> grantedAuthoritiesList = new ArrayList<GrantedAuthority>();

for (Map<String, Object> role : result) {
grantedAuthoritiesList.add(new GrantedAuthorityImpl((String) role.get("AUTHORITY")));
}

return (GrantedAuthority[]) grantedAuthoritiesList.toArray(new GrantedAuthority[grantedAuthoritiesList.size()]);
}

/**
* setter
*
* @param usersByUsernameQuery
*            sql
*
*/
public void setUsersByUsernameQuery(String usersByUsernameQuery) {
this.usersByUsernameQuery = usersByUsernameQuery.toUpperCase();
}

/**
* setter
*
* @param authoritiesByUsernameQuery
*            sql
*/
public void setAuthoritiesByUsernameQuery(String authoritiesByUsernameQuery) {
this.authoritiesByUsernameQuery = authoritiesByUsernameQuery.toUpperCase();
}

}


b、下面这个类用于保存登录账户的相关信息
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;

import org.springframework.security.GrantedAuthority;

public class UserDetails implements org.springframework.security.userdetails.UserDetails, Serializable {
public static final long serialVersionUID = -3072292482513179894L;
public static final String USER_NAME = "USERNAME";
public static final String PASSWORD = "PASSWORD";
public static final String AUTHORITIES = "AUTHORITIES";
public static final String ENABLED = "ENABLED";

private Map<String, Object> userInfo = new HashMap<String, Object>();

public Map<String, Object> getUserInfo() {
return userInfo;
}

public void setUserInfo(Map<String, Object> userInfo) {
this.userInfo = userInfo;
}

public GrantedAuthority[] getAuthorities() {
return (GrantedAuthority[]) userInfo.get(AUTHORITIES);
}

public String getPassword() {
return (String) userInfo.get(PASSWORD);
}

public String getUsername() {
return (String) userInfo.get(USER_NAME);
}

public boolean isAccountNonExpired() {
return true;
}

public boolean isAccountNonLocked() {
return true;
}

public boolean isCredentialsNonExpired() {
return true;
}

public boolean isEnabled() {
Object enabled = userInfo.get(ENABLED);
if (enabled instanceof Number) {
enabled = String.valueOf(((Number) enabled).intValue());
}

if (enabled instanceof String) {
if (enabled.equals("1") || ((String) enabled).equalsIgnoreCase("true")) {
return true;
}
return false;
}
return false;
}

}


c、用户访问资源权限校验类
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.sql.DataSource;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.jdbc.object.MappingSqlQuery;
import org.springframework.security.ConfigAttributeDefinition;
import org.springframework.security.ConfigAttributeEditor;
import org.springframework.security.intercept.web.DefaultFilterInvocationDefinitionSource;
import org.springframework.security.intercept.web.FilterInvocationDefinitionSource;
import org.springframework.security.intercept.web.RequestKey;
import org.springframework.security.util.AntUrlPathMatcher;
import org.springframework.security.util.UrlMatcher;

/**
* spring security jdbc FactoryBean
* @version 1.0
* /**
* 这个类的目的就是构建一个DefaultFilterInvocationDefinitionSource类,
* DefaultFilterInvocationDefinitionSource是默认提供的FilterInvocationDefinitionSource实现类,省力
* 本类继承FactoryBean给DefaultFilterInvocationDefinitionSource构造的两个参数赋值
*/

public class JdbcFilterInvocationDefinitionSourceFactoryBean extends JdbcDaoSupport implements FactoryBean {

private String resourceQuery;

/**
* (non-Javadoc)
*
* @see org.springframework.beans.factory.FactoryBean#isSingleton()
*/
public boolean isSingleton() {//FactoryBean接口方法
return true;
}

/**
* (non-Javadoc)
*
* @see org.springframework.beans.factory.FactoryBean#getObjectType()
*/
public Class<?> getObjectType() {//FactoryBean接口方法
return FilterInvocationDefinitionSource.class;
}

/**
* (non-Javadoc)
*
* @see org.springframework.beans.factory.FactoryBean#getObject()
*/
public Object getObject() {//工厂方法
//取 构造参数一、二
return new DefaultFilterInvocationDefinitionSource(this.getUrlMatcher(), this.buildRequestMap());
}

/**
* 资源-角色的对应关系
*
* @return
*/
@SuppressWarnings("unchecked")
protected Map<String, String> mappingResource() {
Map<String, String> resourceMap = null;
resourceMap = new LinkedHashMap<String, String>();
ResourceMapping resourceMapping = new ResourceMapping(getDataSource(), resourceQuery);

for (Resource resource : (List<Resource>) resourceMapping.execute()) {
String url = resource.getUrl();
String role = resource.getRole();

if (resourceMap.containsKey(url)) {
String value = resourceMap.get(url);
resourceMap.put(url, value + "," + role);
} else {
resourceMap.put(url, role);
}
}
return resourceMap;
}

/**
* buildRequestMap
* 返回DefaultFilterInvocationDefinitionSource构造参数之二
*/
protected LinkedHashMap<RequestKey, ConfigAttributeDefinition> buildRequestMap() {

LinkedHashMap<RequestKey, ConfigAttributeDefinition> requestMap = null;
//这个Map看起来比较唬人,把握两点:key为URL地址,value为允许访问该URL的角色S,URL与ROLE是多对多的关系
requestMap = new LinkedHashMap<RequestKey, ConfigAttributeDefinition>();

ConfigAttributeEditor editor = new ConfigAttributeEditor();

Map<String, String> resourceMap = this.mappingResource();

for (Map.Entry<String, String> entry : resourceMap.entrySet()) {
//key为URL地址,用RequestKey封装
//value为ConfigAttributeEditor,可以理解为一个数组,该数组中存放ConfigAttribute
//每个ConfigAttribute封装一个角色名称
RequestKey key = new RequestKey(entry.getKey(), null);
editor.setAsText(entry.getValue());
requestMap.put(key, (ConfigAttributeDefinition) editor.getValue());
}

return requestMap;
}

/**
* getter
* 返回DefaultFilterInvocationDefinitionSource构造参数之一
*/
protected UrlMatcher getUrlMatcher() {
return new AntUrlPathMatcher(); //这个比RegexUrlPathMatcher简单,所以用这个,不求甚解
}

/**
* setter
*
* @param resourceQuery
*/
public void setResourceQuery(String resourceQuery) {
this.resourceQuery = resourceQuery;
}

/**
* 资源实体类POJO
*/
private class Resource {
private String url;
private String role;

public Resource(String url, String role) {
this.url = url;
this.role = role;
}

public String getUrl() {
return url;
}

public String getRole() {
return role;
}
}

/**
* 资源-角色查询内部类
*
*/
private class ResourceMapping extends MappingSqlQuery {
protected ResourceMapping(DataSource dataSource, String resourceQuery) {
super(dataSource, resourceQuery);
compile();
}

/**
* (non-Javadoc)
*
* @see org.springframework.jdbc.object.MappingSqlQuery#mapRow(java.sql.ResultSet, int)
*/
protected Object mapRow(ResultSet rs, int rownum) throws SQLException {
String url = rs.getString(1);
String role = rs.getString(2);
Resource resource = new Resource(url, role);

return resource;
}
}
}


5、这个实例用到的jsp页面都很简单,这里我也放到附近中不再贴出来了,只用把这些页面放在项目的更目录下就好。

到此应该就没问题了
0
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics