http://simon5408.iteye.com/blog/1973836
MyAccessDecisionManager.java:
/**
*
*/
package com.simonsw.security;
import java.util.Collection;
import java.util.Iterator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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;
/**
* @author Simon Lv
* @since Oct 31, 2013
*/
public class MyAccessDecisionManager implements AccessDecisionManager {
private Logger logger = LoggerFactory.getLogger(getClass());
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.AccessDecisionManager#decide(org.
* springframework.security.core.Authentication, java.lang.Object,
* java.util.Collection)
*/
@Override
public void decide(Authentication authentication, Object obj,
Collection<ConfigAttribute> configAttributes)
throws AccessDeniedException, InsufficientAuthenticationException {
if (configAttributes == null) {
return;
}
// 所请求的资源拥有的权限(一个资源对多个权限)
Iterator<ConfigAttribute> iterator = configAttributes.iterator();
while (iterator.hasNext()) {
ConfigAttribute configAttribute = iterator.next();
// 访问所请求资源所需要的权限
String needPermission = configAttribute.getAttribute();
logger.debug("[MyAccessDecisionManager] needPermission is " + needPermission);
// 用户所拥有的权限authentication
for (GrantedAuthority ga : authentication.getAuthorities()) {
logger.debug("[MyAccessDecisionManager] ga.getAuthority() is " + ga.getAuthority());
if (needPermission.contains((ga.getAuthority()))) {
return;
}
}
}
// 没有权限让我们去捕捉
throw new AccessDeniedException(" 没有权限访问!");
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.AccessDecisionManager#supports(org
* .springframework.security.access.ConfigAttribute)
*/
@Override
public boolean supports(ConfigAttribute arg0) {
return true;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.AccessDecisionManager#supports(java
* .lang.Class)
*/
@Override
public boolean supports(Class<?> arg0) {
return true;
}
}
MyAuthenticationManager.java:
/**
*
*/
package com.simonsw.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import com.simonsw.base.entity.Resource;
import com.simonsw.base.entity.Role;
import com.simonsw.base.entity.RoleResource;
import com.simonsw.base.entity.UserRole;
import com.simonsw.base.entity.Users;
import com.simonsw.base.service.RoleResourceService;
import com.simonsw.base.service.UserRoleService;
import com.simonsw.base.service.UserService;
import com.simonsw.common.util.StringUtils;
/**
* @author Simon Lv
* @since Oct 31, 2013
*/
public class MyAuthenticationManager implements UserDetailsService {
@Autowired
private UserService userService;
@Autowired
private UserRoleService userRoleService;
@Autowired
private RoleResourceService roleResourceService;
private Logger logger = LoggerFactory.getLogger(getClass());
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.userdetails.UserDetailsService#
* loadUserByUsername(java.lang.String)
*/
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
logger.debug("[MyAuthenticationManager] username ==> " + username);
if (!StringUtils.isEmpty(username)) {
throw new UsernameNotFoundException("用户名不能为空!");
}
Users user = userService.getUserByName(username);
Collection<GrantedAuthority> grantedAuths = obtionGrantedAuthorities(user);
boolean enables = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
// 封装成spring security的user
User userdetail = new User(user.getUsername(), user.getPassword(),
enables, accountNonExpired, credentialsNonExpired,
accountNonLocked, grantedAuths);
return userdetail;
}
// 取得用户的权限
private Set<GrantedAuthority> obtionGrantedAuthorities(Users user) {
Set<GrantedAuthority> authSet = new HashSet<GrantedAuthority>();
List<Resource> resources = new ArrayList<Resource>();
Role role;
List<RoleResource> roleResources;
List<UserRole> userRoles = userRoleService.getUserRoleByUserId(user);
for (UserRole userRole : userRoles) {
role = userRole.getRole();
roleResources = roleResourceService.getUserRoleByRoleId(role);
for (RoleResource roleResource : roleResources) {
resources.add(roleResource.getResource());
}
}
for (Resource res : resources) {
authSet.add(new SimpleGrantedAuthority(res.getModelname()));
}
return authSet;
}
}
MyLogoutSuccessHandler.java:
/**
*
*/
package com.simonsw.security;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
/**
* @author Simon Lv
* @since Nov 5, 2013
*/
public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
private Logger logger = LoggerFactory.getLogger(getClass());
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.web.authentication.logout.LogoutSuccessHandler
* #onLogoutSuccess(javax.servlet.http.HttpServletRequest,
* javax.servlet.http.HttpServletResponse,
* org.springframework.security.core.Authentication)
*/
@Override
public void onLogoutSuccess(HttpServletRequest request,
HttpServletResponse response, Authentication authentication)
throws IOException, ServletException {
if (authentication != null) {
logger.debug(authentication.getName() + "Logout==>");
}
response.sendRedirect(request.getContextPath());
}
}
MySecurityFilter.java:
/**
*
*/
package com.simonsw.security;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.access.SecurityMetadataSource;
import org.springframework.security.access.intercept.AbstractSecurityInterceptor;
import org.springframework.security.access.intercept.InterceptorStatusToken;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
/**
* @author Simon Lv
* @since Oct 31, 2013
*/
public class MySecurityFilter extends AbstractSecurityInterceptor implements
Filter {
private Logger logger = LoggerFactory.getLogger(getClass());
// 与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,
// 其他的两个组件,已经在AbstractSecurityInterceptor定义
private FilterInvocationSecurityMetadataSource securityMetadataSource;
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.intercept.AbstractSecurityInterceptor
* #obtainSecurityMetadataSource()
*/
@Override
public SecurityMetadataSource obtainSecurityMetadataSource() {
return this.securityMetadataSource;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
* javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
@Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
FilterInvocation fi = new FilterInvocation(request, response, chain);
invoke(fi);
}
private void invoke(FilterInvocation fi) throws IOException,
ServletException {
logger.debug("[MySecurityFilter] 用户发送请求!");
InterceptorStatusToken token = null;
token = super.beforeInvocation(fi);
try {
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
} finally {
super.afterInvocation(token, null);
}
}
public FilterInvocationSecurityMetadataSource getSecurityMetadataSource() {
return securityMetadataSource;
}
public void setSecurityMetadataSource(
FilterInvocationSecurityMetadataSource securityMetadataSource) {
this.securityMetadataSource = securityMetadataSource;
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
@Override
public void init(FilterConfig arg0) throws ServletException {
}
/*
* (non-Javadoc)
*
* @see javax.servlet.Filter#destroy()
*/
@Override
public void destroy() {
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.intercept.AbstractSecurityInterceptor
* #getSecureObjectClass()
*/
@Override
public Class<?> getSecureObjectClass() {
// 下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误
return FilterInvocation.class;
}
}
MySecurityMetadataSource.java:
/**
*
*/
package com.simonsw.security;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.ConfigAttribute;
import org.springframework.security.access.SecurityConfig;
import org.springframework.security.web.FilterInvocation;
import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
import com.simonsw.base.entity.Role;
import com.simonsw.base.entity.RoleResource;
import com.simonsw.base.entity.UserRole;
import com.simonsw.base.entity.Users;
import com.simonsw.base.service.RoleResourceService;
import com.simonsw.base.service.UserRoleService;
import com.simonsw.base.service.UserService;
/**
* @author Simon Lv
* @since Oct 31, 2013
*/
public class MySecurityMetadataSource implements
FilterInvocationSecurityMetadataSource {
@Autowired
protected UserService userService;
@Autowired
protected UserRoleService userRoleService;
@Autowired
protected RoleResourceService roleResourceService;
private Logger logger = LoggerFactory.getLogger(getClass());
private static LinkedHashMap<String, Collection<ConfigAttribute>> resourceMap = null;
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.SecurityMetadataSource#getAttributes
* (java.lang.Object)
*/
@Override
public Collection<ConfigAttribute> getAttributes(Object object)
throws IllegalArgumentException {
String requestURL = ((FilterInvocation) object).getRequestUrl();
logger.debug("[MySecurityMetadataSource] 请求地址 ===> "
+ ((FilterInvocation) object).getRequestUrl());
if (null == resourceMap) {
loadResourceDefine();
logger.debug("[MySecurityMetadataSource] 我需要的认证 ==> "
+ resourceMap.toString());
}
for (Map.Entry<String, Collection<ConfigAttribute>> entry : resourceMap
.entrySet()) {
logger.debug("[MySecurityMetadataSource] entry.getKey() ===> "
+ entry.getKey());
logger.debug("[MySecurityMetadataSource] request ===> " + requestURL);
if (entry.getKey().equals(requestURL)) {
return entry.getValue();
}
}
return null;
}
/**
* Load all resource
*/
private void loadResourceDefine() {
resourceMap = new LinkedHashMap<String, Collection<ConfigAttribute>>();
Map<String, String> resource = getResource();
for (Map.Entry<String, String> entry : resource.entrySet()) {
Collection<ConfigAttribute> configAttributes = new ArrayList<ConfigAttribute>();
configAttributes.add(new SecurityConfig(entry.getValue()));
resourceMap.put(entry.getKey(),
configAttributes);
}
}
/**
* 加载所有资源与权限的关系
*
* @return
*/
private Map<String, String> getResource() {
Map<String, String> resourceMap = new HashMap<String, String>();
List<Users> users = userService.findAll();
List<UserRole> userRoles;
Role role;
List<RoleResource> roleResources;
userfor: for (Users user : users) {
logger.debug("userId => " + user.getUserid());
userRoles = userRoleService.getUserRoleByUserId(user);
if (userRoles == null) {
logger.debug("userfor => break!!!!");
break userfor;
}
rolefor: for (UserRole userRole : userRoles) {
role = userRole.getRole();
roleResources = roleResourceService.getUserRoleByRoleId(role);
if (roleResources == null) {
break rolefor;
}
for (RoleResource roleResource : roleResources) {
String url = roleResource.getResource().getValue();
if (!resourceMap.containsKey(url)) {
resourceMap.put(url, role.getName());
} else {
String roleName = resourceMap.get(url);
resourceMap.put(url, roleName + "," + role.getName());
}
}
}
}
return resourceMap;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.access.SecurityMetadataSource#
* getAllConfigAttributes()
*/
@Override
public Collection<ConfigAttribute> getAllConfigAttributes() {
// TODO Auto-generated method stub
return null;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.access.SecurityMetadataSource#supports(java
* .lang.Class)
*/
@Override
public boolean supports(Class<?> arg0) {
// TODO Auto-generated method stub
return true;
}
}
MyUsernamePasswordAuthenticationFilter.java:
/**
*
*/
package com.simonsw.security;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import com.simonsw.base.entity.Users;
import com.simonsw.base.service.UserService;
import com.simonsw.common.util.CipherUtil;
import com.simonsw.common.util.StringUtils;
/**
* @author Simon Lv
* @since Oct 31, 2013
*/
public class MyUsernamePasswordAuthenticationFilter extends
UsernamePasswordAuthenticationFilter {
@Autowired
protected UserService userService;
private Logger logger = LoggerFactory.getLogger(getClass());
public static final String VALIDATE_CODE = "validateCode";
public static final String USERNAME = "username";
public static final String PASSWORD = "password";
@Override
public Authentication attemptAuthentication(HttpServletRequest request,
HttpServletResponse response) {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: "
+ request.getMethod());
}
// checkValidateCode(request);
String username = obtainUsername(request);
logger.debug("[MyUsernamePasswordAuthenticationFilter] username ==> "+ username);
String password = CipherUtil.generatePassword(obtainPassword(request));
logger.debug("[MyUsernamePasswordAuthenticationFilter] password ==> "+ password);
// 验证用户账号与密码是否对应
username = username.trim();
Users users = userService.getUserByName(username);
if (users == null || !users.getPassword().equals(password)) {
throw new AuthenticationServiceException(
"password or username is notEquals");
}
// UsernamePasswordAuthenticationToken实现 Authentication
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(
username, password);
// Place the last username attempted into HttpSession for views
// 允许子类设置详细属性
setDetails(request, authRequest);
// 运行UserDetailsService的loadUserByUsername 再次封装Authentication
return this.getAuthenticationManager().authenticate(authRequest);
}
protected void checkValidateCode(HttpServletRequest request) {
HttpSession session = request.getSession();
String sessionValidateCode = obtainSessionValidateCode(session);
// 让上一次的验证码失效
session.setAttribute(VALIDATE_CODE, null);
String validateCodeParameter = obtainValidateCodeParameter(request);
if (StringUtils.isEmpty(validateCodeParameter)
|| !sessionValidateCode.equalsIgnoreCase(validateCodeParameter)) {
throw new AuthenticationServiceException("validateCode.notEquals");
}
}
private String obtainValidateCodeParameter(HttpServletRequest request) {
Object obj = request.getParameter(VALIDATE_CODE);
return null == obj ? "" : obj.toString();
}
protected String obtainSessionValidateCode(HttpSession session) {
Object obj = session.getAttribute(VALIDATE_CODE);
return null == obj ? "" : obj.toString();
}
@Override
protected String obtainUsername(HttpServletRequest request) {
Object obj = request.getParameter(USERNAME);
return null == obj ? "" : obj.toString();
}
@Override
protected String obtainPassword(HttpServletRequest request) {
Object obj = request.getParameter(PASSWORD);
return null == obj ? "" : obj.toString();
}
}
security.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/security" 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-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<debug />
<global-method-security pre-post-annotations="enabled" />
<!-- 此目录下不需要过滤 -->
<http pattern="/js/**" security="none" />
<http pattern="/css/**" security="none" />
<http pattern="/images/**" security="none" />
<http pattern="/login" security="none" />
<http use-expressions="true" entry-point-ref="authenticationProcessingFilterEntryPoint">
<!-- if no limit, go to 403 page -->
<access-denied-handler error-page="/403" />
<!-- Logout -->
<logout invalidate-session="true" logout-url="/logout"
success-handler-ref="myLogoutSuccessHandler" />
<!-- 实现免登陆验证 -->
<remember-me />
<session-management invalid-session-url="/">
<concurrency-control max-sessions="10"
error-if-maximum-exceeded="true" />
</session-management>
<custom-filter ref="loginFilter" position="FORM_LOGIN_FILTER" />
<custom-filter ref="securityFilter" before="FILTER_SECURITY_INTERCEPTOR" />
</http>
<!-- 登录验证器 -->
<beans:bean id="loginFilter"
class="com.simonsw.security.MyUsernamePasswordAuthenticationFilter">
<!-- 处理登录 -->
<beans:property name="filterProcessesUrl" value="/user/login"></beans:property>
<beans:property name="authenticationSuccessHandler"
ref="loginLogAuthenticationSuccessHandler"></beans:property>
<beans:property name="authenticationFailureHandler"
ref="simpleUrlAuthenticationFailureHandler"></beans:property>
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
</beans:bean>
<beans:bean id="loginLogAuthenticationSuccessHandler"
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/"></beans:property>
</beans:bean>
<beans:bean id="simpleUrlAuthenticationFailureHandler"
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/"></beans:property>
</beans:bean>
<!-- 认证过滤器 -->
<beans:bean id="securityFilter" class="com.simonsw.security.MySecurityFilter">
<!-- 用户拥有的权限 -->
<beans:property name="authenticationManager" ref="myAuthenticationManager" />
<!-- 用户是否拥有所请求资源的权限 -->
<beans:property name="accessDecisionManager" ref="myAccessDecisionManager" />
<!-- 资源与权限对应关系 -->
<beans:property name="securityMetadataSource" ref="mySecurityMetadataSource" />
</beans:bean>
<!-- 实现了UserDetailsService的Bean -->
<authentication-manager alias="myAuthenticationManager">
<authentication-provider user-service-ref="myAuthenticationManagers" />
</authentication-manager>
<beans:bean id="myAccessDecisionManager"
class="com.simonsw.security.MyAccessDecisionManager"></beans:bean>
<beans:bean id="mySecurityMetadataSource"
class="com.simonsw.security.MySecurityMetadataSource">
</beans:bean>
<beans:bean id="myAuthenticationManagers"
class="com.simonsw.security.MyAuthenticationManager">
</beans:bean>
<beans:bean id="myLogoutSuccessHandler" class="com.simonsw.security.MyLogoutSuccessHandler" />
<!-- 未登录的切入点 -->
<beans:bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">
<beans:property name="loginFormUrl" value="/login"></beans:property>
</beans:bean>
</beans:beans>
web.xml:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-security.xml</param-value>
</context-param>
<!-- Spring Security Session -->
<listener>
<listener-class>org.springframework.security.web.session.HttpSessionEventPublisher</listener-class>
</listener>
<!-- Spring security Filter -->
<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>
启动Tomcat,登录正常工作。
具体想看源代码,请访问GitHub网站上的源代码:
https://github.com/simon5408/DummyProj