您的位置:首页 > 编程语言 > Java开发

spring security3教程系列--自定义权限管理

2014-09-18 09:00 274 查看
本文章摘编、转载需要注明来源 http://write.blog.csdn.net/postedit/8575062
spring security3中的权限管理虽然有文件可配置,但是很多时候我们是需要数据库的支持,下面我演示下如何配置自定义权限管理,这个时候需要重新实现下面的类,

该文章适合对spring security3 有一定理解的人员

AccessDecisionManager是验证资源跟角色之间的关系,由于我个人不太喜欢用标签化,因为感觉灵活性不够好,所以我统一是用bean方式,至于用bean来描述是需要对security的

过滤链流程和各个属性依赖关系比较熟悉的了解才可以配置成功,这样灵活性大大加强

[java] view
plaincopy

/**

*

* @author shadow

* @email 124010356@qq.com

* @create 2012.04.28

*/

public class AccessDecisionManagerImpl implements AccessDecisionManager {

public void decide(Authentication authentication, Object object,

Collection<ConfigAttribute> attributes)

throws AccessDeniedException, InsufficientAuthenticationException {

if (null == attributes)

return;

for (ConfigAttribute attribute : attributes) {

String needRole = ((SecurityConfig) attribute).getAttribute();

// authority为用户所被赋予的权限, needRole 为访问相应的资源应该具有的权限。

for (GrantedAuthority grantedAuthority : authentication

.getAuthorities()) {

if (needRole.equals(grantedAuthority.getAuthority()))

return;

}

}

throw new AccessDeniedException("权限不足!");

}

public boolean supports(ConfigAttribute attribute) {

return true;

}

public boolean supports(Class<?> clazz) {

return true;

}

}

SecurityMetadataSource是角色跟资源加载器,项目启动的时候会先执行资源跟角色关联加载提供给security以便认证

[java] view
plaincopy

/**

* 初始化时加载角色资源关联数据

*

* @author shadow

* @email 124010356@qq.com

* @create 2012.04.28

*/

public class SecurityMetadataSourceExtendImpl implements

SecurityMetadataSourceExtend {

private boolean expire = false; // 过期标识

private RoleService roleService; // 角色服务类

private ResourceService resourceService; // 资源服务类

private RequestMatcher requestMatcher; // 匹配规则

private String matcher; // 规则标识

private Map<String, Collection<ConfigAttribute>> kv = new HashMap<String, Collection<ConfigAttribute>>(); // 资源集合

public RoleService getRoleService() {

return roleService;

}

@javax.annotation.Resource

public void setRoleService(RoleService roleService) {

this.roleService = roleService;

}

public ResourceService getResourceService() {

return resourceService;

}

@javax.annotation.Resource

public void setResourceService(ResourceService resourceService) {

this.resourceService = resourceService;

}

public boolean supports(Class<?> clazz) {

return true;

}

// 初始化方法时候从数据库中读取资源

// @PostConstruct

public void init() {

load();

}

public Collection<ConfigAttribute> getAllConfigAttributes() {

Set<ConfigAttribute> attributes = new HashSet<ConfigAttribute>();

for (Map.Entry<String, Collection<ConfigAttribute>> entry : kv

.entrySet()) {

attributes.addAll(entry.getValue());

}

return attributes;

}

public Collection<ConfigAttribute> getAttributes(Object object)

throws IllegalArgumentException {

HttpServletRequest request = ((FilterInvocation) object).getRequest();

// System.out.println("requestUrl is " + request.getRequestURI());

// 检测是否刷新了资源

if (isExpire()) {

// 清空原本资源

kv.clear();

expire = false;

}

// 如果资源Map为空的时候则重新加载一次

if (null == kv || kv.isEmpty())

load();

// 检测请求与当前资源匹配的正确性

Iterator<String> iterator = kv.keySet().iterator();

while (iterator.hasNext()) {

String uri = iterator.next();

if (matcher.toLowerCase().equals("ant")) {

requestMatcher = new AntPathRequestMatcher(uri);

}

if (matcher.toLowerCase().equals("regex")) {

requestMatcher = new RegexRequestMatcher(uri, request

.getMethod(), true);

}

if (requestMatcher.matches(request))

return kv.get(uri);

}

return null;

}

/**

* 加载所有资源与权限的关系

*/

public void load() {

List<Resource> resources = this.resourceService.loadForAll();

for (Resource resource : resources) {

List<Role> roles = this.roleService.findByResourceId(resource

.getId());

kv.put(resource.getContent(), list2Collection(roles));

}

}

/**

* 将List<Role>集合转换为框架需要的Collection<ConfigAttribute>集合

*

* @param roles

* @return Collection<ConfigAttribute>

*/

private Collection<ConfigAttribute> list2Collection(List<Role> roles) {

List<ConfigAttribute> list = new ArrayList<ConfigAttribute>();

for (Role role : roles)

list.add(new SecurityConfig(role.getName()));

return list;

}

public void setMatcher(String matcher) {

this.matcher = matcher;

}

public boolean isExpire() {

return expire;

}

public void expireNow() {

this.expire = true;

}

}

FilterSecurityInterceptor是资源访问第一个需要经过的过滤器,这个类我们还是不需要重写了,直接使用spring security提供的比较

具体路径org.springframework.security.web.access.intercept.FilterSecurityInterceptor

UserDetailsService这个类security的form表单登录处理

[java] view
plaincopy

/**

* SPRING SECURITY3用户登录处理

*

* @author shadow

* @email 124010356@qq.com

* @create 2012.04.28

*/

public class UserDetailsServiceImpl implements UserDetailsService {

private UserService userService;

private RoleService roleService;

public UserService getUserService() {

return userService;

}

@Resource

public void setUserService(UserService userService) {

this.userService = userService;

}

public RoleService getRoleService() {

return roleService;

}

@Resource

public void setRoleService(RoleService roleService) {

this.roleService = roleService;

}

public UserDetails loadUserByUsername(String username)

throws UsernameNotFoundException {

// 使用User服务类查询数据用户是否存在,如不存在或密码错误则抛出对应的异常

List<User> users = this.userService.findByUserName(username);

if (null == users || users.isEmpty())

throw new UsernameNotFoundException("用户/密码错误,请重新输入!");

User user = users.get(0);

List<Role> roles = this.roleService.findByUserId(user.getId());

if (null == roles || roles.isEmpty())

throw new UsernameNotFoundException("权限不足!");

// 把权限赋值给当前对象

Collection<GrantedAuthority> gaRoles = new ArrayList<GrantedAuthority>();

for (Role role : roles) {

gaRoles.add(new SimpleGrantedAuthority(role.getName()));

}

user.setAuthorities(gaRoles);

return user;

}

}

三个类都准备好了现在去配置xml文件,先声明三个类的bean

[java] view
plaincopy

<!-- 自定义UserDetailsService认证 -->

<bean id="userDetailsService"

class="com.shadow.security.service.UserDetailsServiceImpl" />

<!-- 自定义资源权限关系认证 -->

<bean id="accessDecisionManager"

class="com.shadow.security.service.AccessDecisionManagerImpl" />

<!-- 自定义资源权限关系集合 -->

<bean id="securityMetadataSource"

class="com.shadow.security.service.SecurityMetadataSourceExtendImpl">

<property name="matcher" value="ant" />

</bean>

然后配置filterSecurityInterceptor,我们不再用security提供的实现类,而是使用我们刚刚写的实现类

[java] view
plaincopy

<!-- 自定义认证管理,资源,权限 -->

<bean id="filterSecurityInterceptor"

class="org.springframework.security.web.access.intercept.FilterSecurityInterceptor">

<property name="authenticationManager"

ref="authenticationManager" />

<property name="accessDecisionManager"

ref="accessDecisionManager" />

<property name="securityMetadataSource"

ref="securityMetadataSource" />

</bean>

至于authenticationManager的注入如下(rememberMeAuthenticationProvider可不注入,这个东西是记住密码功能需要用到的玩意)

[java] view
plaincopy

<!-- 认证管理器 -->

<bean id="authenticationManager"

class="org.springframework.security.authentication.ProviderManager">

<property name="providers">

<list>

<ref bean="daoAuthenticationProvider" />

<ref bean="rememberMeAuthenticationProvider" />

</list>

</property>

</bean>

<!-- 登录认证处理 -->

<bean id="daoAuthenticationProvider"

class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">

<property name="hideUserNotFoundExceptions" value="false"/>

<property name="userDetailsService" ref="userDetailsService" />

<property name="passwordEncoder" ref="passwordEncoder" />

<property name="saltSource" ref="saltSource" />

</bean>

<!-- 加密方式 -->

<bean id="passwordEncoder"

class="org.springframework.security.authentication.encoding.Md5PasswordEncoder" />

<!-- 配置加密盐值 -->

<bean id="saltSource"

class="org.springframework.security.authentication.dao.ReflectionSaltSource">

<property name="userPropertyToUse" value="username" />

</bean>

然后配置我们的过滤链

[java] view
plaincopy

<!-- 自定义SPRING SECURITY过滤链 -->

<bean id="securityFilterChainProxy"

class="org.springframework.security.web.FilterChainProxy">

<constructor-arg>

<list>

<security:filter-chain pattern="/services/**"

filters="none" />

<security:filter-chain pattern="/test*" filters="none" />

<security:filter-chain pattern="/**"

filters="concurrentSessionFilter,securityContextPersistenceFilter,logoutFilter,usernamePasswordAuthenticationFilter,rememberMeAuthenticationFilter,sessionManagementFilter,anonymousAuthFilter,exceptionTranslationFilter,filterSecurityInterceptor" />

</list>

</constructor-arg>

</bean>

至于过滤链里的其他filter我就不一一列出来了,然后大概流程就这样可以了,然后页面就搞个普通的security表单,提交的时候会进入到我们的userDetailsService实现类里验证你输入的账号密码是否一致,至于主要三个model就不出代码了,相信大家也应该明白,就是User,Role,Resource三者之间的关联
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: