这里给出一个简单的安全验证的实现例子,先说一下需求:
1.通过登录页面进行登录
2.用户登录前访问被保护的地址时自动跳转到登录页面
3.用户信息存储在数据表中
4.用户权限信息存在在数据表中
5.用户登录成功后访问没有权限访问的地址时跳转到登录页面
ok,以上就是一个基本的需求了,大部分的系统都是基于该需求实现登录模块的。
给出实现之前,先简单说明一下springsecurity的原理,
1.AccessDecisionManager
和我们一般实现登录验证采用filter的方式一样,springsecurity也是一个过滤器,当请求被springsecurity拦截后,会先对用户请求的资源进行安全认证,如果用户有权访问该资源,则放行,否则将阻断用户请求或提供用户登录,
AffirmativeBased,既只要有一个投票器通过验证就允许用户访问,
所以如果希望实现自己的权限验证策略,实现自己的投票器是一个很好的选择。
2.UserDetailsService
UserDetailsService来验证用户是否合法,既验证用户名和密码是否正确,同时验证用户是否具备相应的资源权限,
即对应的access的value。
如果用户验证通过,则由AccessDecisionManager来决定是否用户可以访问该资源。
下面给出具体实现:
web.xml
基本上都是这样配置,就不废话了。
<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 > *.do*" access = "HODLE" />
<logout logout-url = "/logout.do" invalidate-session = "true"
logout-success-url = "/logout.jsp" />
<form-login login-page = "/index.do" default-target-url = "/frame.do"
always-use-default-target = "true" authentication-failure-url = "/index.do?login_error=1" />
<session-management >
<concurrency-control max-sessions = "1" />
</session-management >
</http >
<beans:bean id = "loggerListener"
class = "org.springframework.security.authentication.event.LoggerListener" />
<authentication-manager >
<authentication-provider user-service-ref = "userService" >
<password-encoder hash = "md5" />
</authentication-provider >
</authentication-manager >
<beans:bean id = "userService" class = "com.piaoyi.common.security.UserService" />
<beans:bean id = "accessDecisionManager"
class = "org.springframework.security.access.vote.AffirmativeBased" >
<beans:property name = "decisionVoters" >
<beans:list >
<beans:bean class = "org.springframework.security.access.vote.RoleVoter" />
<beans:bean
class = "org.springframework.security.access.vote.AuthenticatedVoter" />
<beans:bean class = "com.piaoyi.common.security.DynamicRoleVoter" />
</beans:list >
</beans:property >
</beans:bean >
</beans:beans >
UserService.java
public class UserService implements UserDetailsService{
@Autowired
private ISystemUserService userService;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// TODO Auto-generated method stub
SystemUser user = userService.findById(username);
if (user == null )
throw new UsernameNotFoundException( "The user name " + username
+ " can not be found!" );
List resultAuths = new ArrayList();
//增加access中配置的权限,实际上这里就是让所有登陆用户都具备该权限,
//而真正的资源权限验证留给AccessDecisionManager来决定
resultAuths.add(new GrantedAuthorityImpl( "HODLE" ));
//验证用户名和密码是否正确,以及是否权限正确
return new User(username, user.getPassword().toLowerCase(), user.isStatus(), true ,
true , true , resultAuths);
}
}
DynamicRoleVoter.java
public class DynamicRoleVoter implements
AccessDecisionVoter {
@Autowired
private ISystemUserService userService;
private PathMatcher pathMatcher = new AntPathMatcher();
@SuppressWarnings ( "unchecked" )
public boolean supports(Class clazz) {
return true ;
}
public boolean supports(ConfigAttribute attribute) {
return true ;
}
public int vote(Authentication authentication, Object object,
java.util.Collection arg2) {
int result = ACCESS_ABSTAIN;
if (!(object instanceof FilterInvocation))
return result;
FilterInvocation invo = (FilterInvocation) object;
String url = invo.getRequestUrl();//当前请求的URL
Set authorities = null ;
String userId = authentication.getName();
//获得当前用户的可访问资源,自定义的查询方法,之后和当前请求资源进行匹配,成功则放行,否则拦截
authorities = loadUserAuthorities(userService.findById(userId));
Map> urlAuths = authService.getUrlAuthorities();
Set keySet = urlAuths.keySet();
for (String key : keySet) {
boolean matched = pathMatcher.match(key, url);
if (!matched)
continue ;
Set mappedAuths = urlAuths.get(key);
if (contain(authorities, mappedAuths)) {
result = ACCESS_GRANTED;
break ;
}
}
return result;
}
protected boolean contain(Set authorities,
Set mappedAuths) {
if (CollectionUtils.isEmpty(mappedAuths)
|| CollectionUtils.isEmpty(authorities))
return false ;
for (GrantedAuthority item : authorities) {
if (mappedAuths.contains(item.getAuthority()))
return true ;
}
return false ;
}
}