Spring Security3.1例子这几天学习了一下Spring Security3.1,从官网下载了Spring Security3.1版本进行练习
Spring Security3.1例子
这几天学习了一下Spring Security3.1,从官网下载了Spring Security3.1版本进行练习,经过多次尝试才摸清了其中的一些原理。本人不才,希望能帮助大家。还有,这次我第二次写博客啊,文体不是很行。希望能让观看者不产生疲惫的感觉,我已经心满意足了。
一、数据库结构
???? 先来看一下数据库结构,采用的是基于角色-资源-用户的权限管理设计。(MySql数据库)
??? 为了节省篇章,只对比较重要的字段进行注释。
??? 1.用户表Users
??? CREATE TABLE `users` (
????? ?-- 账号是否有限 1. 是 0.否
?????? `enable` int(11) default NULL,
?????? `password` varchar(255) default NULL,
? ???? `account` varchar(255) default NULL,
?????? `id` int(11) NOT NULL auto_increment,
?????? PRIMARY KEY? (`id`)
??? )
?
?? 2.角色表Roles
???CREATE TABLE `roles` (
???? `enable` int(11) default NULL,
???? `name` varchar(255) default NULL,
???? `id` int(11) NOT NULL auto_increment,
???? PRIMARY KEY? (`id`)
?? )
?
?? 3 用户_角色表users_roles
?? CREATE TABLE `users_roles` (
???? --用户表的外键
???? `uid` int(11) default NULL,
???? --角色表的外键
???? `rid` int(11) default NULL,
???? `urId` int(11) NOT NULL auto_increment,
???? PRIMARY KEY? (`urId`),
???? KEY `rid` (`rid`),
???? KEY `uid` (`uid`),
??? CONSTRAINT `users_roles_ibfk_1` FOREIGN KEY (`rid`) REFERENCES `roles` (`id`),
??? CONSTRAINT `users_roles_ibfk_2` FOREIGN KEY (`uid`) REFERENCES `users` (`id`)
?? )
?
?? 4.资源表resources
???CREATE TABLE `resources` (
???? `memo` varchar(255) default NULL,
???? --?权限所对应的url地址
???? `url` varchar(255) default NULL,
???? --优先权
???? `priority` int(11) default NULL,
???? --类型
???? `type` int(11) default NULL,
???? --权限所对应的编码,例201代表发表文章
???? `name` varchar(255) default NULL,
???? `id` int(11) NOT NULL auto_increment,
???? PRIMARY KEY? (`id`)
?? )
?
?? 5.角色_资源表roles_resources
??? CREATE TABLE `roles_resources` (
????? `rsid` int(11) default NULL,
????? `rid` int(11) default NULL,
????? `rrId` int(11) NOT NULL auto_increment,
????? PRIMARY KEY? (`rrId`),
????? KEY `rid` (`rid`),
????? KEY `roles_resources_ibfk_2` (`rsid`),
????? CONSTRAINT `roles_resources_ibfk_2` FOREIGN KEY (`rsid`) REFERENCES `resources` (`id`),
????? CONSTRAINT `roles_resources_ibfk_1` FOREIGN KEY (`rid`) REFERENCES `roles` (`id`)
????? )
?
? 二、系统配置
?? 所需要的jar包,请自行到官网下载,我用的是Spring Security3.1.0.RC1版的。把dist下的除了源码件包导入就行了。还有那些零零碎的?? 数据库驱动啊,log4j.jar等等,我相信在用Spring Security之前,大家已经会的了。
? 1) web.xml
?
我们自定义的Filter必须在它之前,过滤客服请求。接下来看下我们最主要的myFilter吧。
?
3)myFilter
? (1) MySecurityFilter.java 过滤用户请求
?
[java] view plaincopy
- public?class?MySecurityFilter?extends?AbstractSecurityInterceptor?implements?Filter?{??????//与applicationContext-security.xml里的myFilter的属性securityMetadataSource对应,??
- ????//其他的两个组件,已经在AbstractSecurityInterceptor定义??????private?FilterInvocationSecurityMetadataSource?securityMetadataSource;??
- ??????@Override??
- ????public?SecurityMetadataSource?obtainSecurityMetadataSource()?{??????????return?this.securityMetadataSource;??
- ????}????
- ????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?{??????????//?object为FilterInvocation对象??
- ??????????????????//super.beforeInvocation(fi);源码??????????//1.获取请求资源的权限??
- ????????//执行Collection<ConfigAttribute>?attributes?=?SecurityMetadataSource.getAttributes(object);??????????//2.是否拥有权限??
- ????????//this.accessDecisionManager.decide(authenticated,?object,?attributes);??????????InterceptorStatusToken?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;??????}??
- ??????????public?void?init(FilterConfig?arg0)?throws?ServletException?{??
- ????????//?TODO?Auto-generated?method?stub??????}??
- ??????????public?void?destroy()?{??
- ????????//?TODO?Auto-generated?method?stub????????????
- ????}????
- ????@Override??????public?Class<??extends?Object>?getSecureObjectClass()?{??
- ????????//下面的MyAccessDecisionManager的supports方面必须放回true,否则会提醒类型错误??????????return?FilterInvocation.class;??
- ????}??}??
?
? 核心的InterceptorStatusToken token = super.beforeInvocation(fi);会调用我们定义的accessDecisionManager:decide(Object object)和securityMetadataSource
? :getAttributes(Object object)方法。
?
?(2)MySecurityMetadataSource.java
?
[java] view plaincopy
- //1?加载资源与权限的对应关系??public?class?MySecurityMetadataSource?implements?FilterInvocationSecurityMetadataSource?{??
- ????//由spring调用??????public?MySecurityMetadataSource(ResourcesDao?resourcesDao)?{??
- ????????this.resourcesDao?=?resourcesDao;??????????loadResourceDefine();??
- ????}????
- ????private?ResourcesDao?resourcesDao;??????private?static?Map<String,?Collection<ConfigAttribute>>?resourceMap?=?null;??
- ??????public?ResourcesDao?getResourcesDao()?{??
- ????????return?resourcesDao;??????}??
- ??????public?void?setResourcesDao(ResourcesDao?resourcesDao)?{??
- ????????this.resourcesDao?=?resourcesDao;??????}??
- ??????public?Collection<ConfigAttribute>?getAllConfigAttributes()?{??
- ????????//?TODO?Auto-generated?method?stub??????????return?null;??
- ????}????
- ????public?boolean?supports(Class<?>?clazz)?{??????????//?TODO?Auto-generated?method?stub??
- ????????return?true;??????}??
- ????//加载所有资源与权限的关系??????private?void?loadResourceDefine()?{??
- ????????if(resourceMap?==?null)?{??????????????resourceMap?=?new?HashMap<String,?Collection<ConfigAttribute>>();??
- ????????????List<Resources>?resources?=?this.resourcesDao.findAll();??????????????for?(Resources?resource?:?resources)?{??
- ????????????????Collection<ConfigAttribute>?configAttributes?=?new?ArrayList<ConfigAttribute>();??????????????????????????????????//以权限名封装为Spring的security?Object??
- ????????????????ConfigAttribute?configAttribute?=?new?SecurityConfig(resource.getName());??????????????????configAttributes.add(configAttribute);??
- ????????????????resourceMap.put(resource.getUrl(),?configAttributes);??????????????}??
- ????????}????????????
- ????????Set<Entry<String,?Collection<ConfigAttribute>>>?resourceSet?=?resourceMap.entrySet();??????????Iterator<Entry<String,?Collection<ConfigAttribute>>>?iterator?=?resourceSet.iterator();??
- ??????????????}??
- ????//返回所请求资源所需要的权限??????public?Collection<ConfigAttribute>?getAttributes(Object?object)?throws?IllegalArgumentException?{??
- ??????????????????String?requestUrl?=?((FilterInvocation)?object).getRequestUrl();??
- ????????System.out.println("requestUrl?is?"?+?requestUrl);??????????if(resourceMap?==?null)?{??
- ????????????loadResourceDefine();??????????}??
- ????????return?resourceMap.get(requestUrl);??????}??
- ??}??
?
?这里的resourcesDao,熟悉Dao设计模式和Spring 注入的朋友应该看得明白。
?
(3)MyUserDetailServiceImpl.java
?
[java] view plaincopy
- public?class?MyUserDetailServiceImpl?implements?UserDetailsService?{????????
- ????private?UsersDao?usersDao;??????public?UsersDao?getUsersDao()?{??
- ????????return?usersDao;??????}??
- ??????public?void?setUsersDao(UsersDao?usersDao)?{??
- ????????this.usersDao?=?usersDao;??????}??
- ??????????public?UserDetails?loadUserByUsername(String?username)?throws?UsernameNotFoundException?{??
- ????????System.out.println("username?is?"?+?username);??????????Users?users?=?this.usersDao.findByName(username);??
- ????????if(users?==?null)?{??????????????throw?new?UsernameNotFoundException(username);??
- ????????}??????????Collection<GrantedAuthority>?grantedAuths?=?obtionGrantedAuthorities(users);??
- ??????????????????boolean?enables?=?true;??
- ????????boolean?accountNonExpired?=?true;??????????boolean?credentialsNonExpired?=?true;??
- ????????boolean?accountNonLocked?=?true;????????????
- ????????User?userdetail?=?new?User(users.getAccount(),?users.getPassword(),?enables,?accountNonExpired,?credentialsNonExpired,?accountNonLocked,?grantedAuths);??????????return?userdetail;??
- ????}????????
- ????//取得用户的权限??????private?Set<GrantedAuthority>?obtionGrantedAuthorities(Users?user)?{??
- ????????Set<GrantedAuthority>?authSet?=?new?HashSet<GrantedAuthority>();??????????Set<Roles>?roles?=?user.getRoles();??
- ??????????????????for(Roles?role?:?roles)?{??
- ????????????Set<Resources>?tempRes?=?role.getResources();??????????????for(Resources?res?:?tempRes)?{??
- ????????????????authSet.add(new?GrantedAuthorityImpl(res.getName()));??s???????????}??
- ????????}??????????return?authSet;??
- ????}??}??
?
?
(4) MyAccessDecisionManager.java
[java] view plaincopy
- public?class?MyAccessDecisionManager?implements?AccessDecisionManager?{????????
- ????public?void?decide(Authentication?authentication,?Object?object,?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();??
- ????????????System.out.println("needPermission?is?"?+?needPermission);??????????????//用户所拥有的权限authentication??
- ????????????for(GrantedAuthority?ga?:?authentication.getAuthorities())?{??????????????????if(needPermission.equals(ga.getAuthority()))?{??
- ????????????????????return;??????????????????}??
- ????????????}??????????}??
- ????????//没有权限??????????throw?new?AccessDeniedException("?没有权限访问!?");??
- ????}????
- ????public?boolean?supports(ConfigAttribute?attribute)?{??????????//?TODO?Auto-generated?method?stub??
- ????????return?true;??????}??
- ??????public?boolean?supports(Class<?>?clazz)?{??
- ????????//?TODO?Auto-generated?method?stub??????????return?true;??
- ????}????????
- }??
?
?
三、流程
?1)容器启动(MySecurityMetadataSource:loadResourceDefine加载系统资源与权限列表)
?2)用户发出请求
?3)过滤器拦截(MySecurityFilter:doFilter)
?4)取得请求资源所需权限(MySecurityMetadataSource:getAttributes)
?5)匹配用户拥有权限和请求权限(MyAccessDecisionManager:decide),如果用户没有相应的权限,
?????执行第6步,否则执行第7步。
?6)登录
?7)验证并授权(MyUserDetailServiceImpl:loadUserByUsername)
?8)重复4,5
?