一个zhuo'li自定义Spring 权限框架

权限控制

认证授权

概念

认证:系统提供的用于识别用户身份的功能,通常提供用户名和密码进行登录操作其实就是在进行认证,认证的目的是让系统知道是谁

授权:用户认证成功后,需要为用户授权,其实就是指定当前用户可以操作哪些功能

分析

权限控制的基本实现思路:

先通过用户名和密码对用户进行认证,认证就是判断当前用户是否是系统用户

然后再根据用户ID或用户名获取权限信息,即授权信息

授权信息是用户角色及权限标识的集合,把用户的角色,权限标识集合与用户关联,最终放入集合中.

每个用户的授权信息,只需要在登录的时候加载一次即可,所以我们把授权的代码放在登录成功之后执行

认证授权实现

UserService

修改login方法, 添加授权(加载用户的权限)

//判断查询的用户名和密码是否有值

if(user!=null){

//先创建一个list集合,用来存储用户加载的角色

Listlist=newArraryList<>();

//调用Dao层加载用户拥有的角色

RoleDaoroledao=SqlSessiopn.getMapping(RoleDao.class);

//传入用户的id属性,返回Role集合

ListroleList=roledao.findByUid(user.getId);

//判断该用户是否有权限 (Dao层返回的对象是否有值)

if(roleList!=null&&rolelist.size()>0){

//加载每个用户对应的角色的权限资源

PermissionDaopermission=sqlSession.getMapper(PermissionDao.class);


for (Rolerole:roleList){

//循环将role的keyWord存入list集合

list.add(role.getKeyword());

//调用Dao层,传入roleid作为参数

ListpermissionList=permission.findByRoledId(role.getId);

if  (permissionList!=null){

for (Permissionpermission:permissionList){

list.add(permission.getKeyword());

               }

           }

       }

   }

//将list集合作为参数修改到user中的authorityList集合属性中

user.setAuthorityList(list)



}

RoleDao

ListfindByUid(Integerid);//调用映射文件对应的id标签

RoleDao.xml

select * from t_role where id in(select role_id from tr_user_role where user_id=#{uid})  

PermissionDao

ListfindByRoleId(Integerid);//调用映射文件对应的id标签

PermissionDao.xml

  select * from t_permission where id in(select permission_id from tr_role_permission where role_id=#{roleId})

自定义权限框架流程

权限控制实现步骤

配置权限资源

如果一个资源,需要指定权限/角色才能访问,那么:要把资源和权限/角色的关系进行配置

可以采用两张配置结合使用:

XML配置 : 用于对一些资源文件(如:html文件)的权限进行配置

注解配置 : 用于对web层方法的权限进行配置

加载配置

当服务器启动时 ,要获取资源所需要的权限配置

拦截请求 ,判断

当前登录的用户拥有的权限,是否包含了访问资源所需要的权限

自定义框架-基于XML

创建配置文件

文件名称:mm-security.xml

文件位置:放在resources目录下

文件说明:

beans:根标签

security标签:一个标签,配置一个资源所需要的角色

pattern:资源路径,这里配置的是html页面的路径

has_role:资源所需要的角色。多个角色之间,用逗号隔开

表示:访问pattern资源,用户必须有has_role中定义的角色之一;否则无权限

"/>

创建过滤器

publicclassSecurityFilterimplementsFilter{

//创建一个map集合用来存存储配置文件中的pattern属性(键) 和 has_role属性(值)

privateMapmap=newHashMap<>();

@Override

publicvoidinit(FilterConfigfilterConfig)throwsServletException{

//需要加载配置文件mm-security.xml 得到每个页面资源可以访问的角色

InputStreaminputStream=null;

try{

//通过过滤器的FilterConfig对象,可以得到web.xml里,配置的初始化参数

StringconfigLocation=filterConfig.getInitParameter("configLocation");

inputStream=this.getClass().getClassLoader().getResourceAsStream(configLocation);

//读取解析xml文件,得到里边的配置  使用的方法:dom4j

SAXReaderreader=newSAXReader();

Documentdocument=reader.read(inputStream);

/*  方法一

//获取xml文件里所有的security标签

//先找到根标签 ,再根据根标签找到里边的子标签

Element rootElement=document.getRootElement();

rootElement.element("security");*/

//方法二  用xpath表达式 //security,表示从xml文件里全文搜索security标签

Listsecurity=document.selectNodes("//security");

for(ElementsecurityElement:security){

//获取security标签的pattern属性值:资源路径

Stringpattern=securityElement.attributeValue("pattern");

//获取security标签的has_role属性值:哪些角色可以访问

Stringhas_role=securityElement.attributeValue("has_role");

//将读取的数据存储到Map集合,以资源路径作为键,以has_role的属性值作为值

map.put(pattern,has_role);

           }

}catch(Exceptione) {

e.printStackTrace();

}finally{

try{

if(inputStream!=null) {

//关闭输入流

inputStream.close();

               }

}catch(IOExceptione) {

e.printStackTrace();

           }

       }

   }

/**

* 权限过滤: 判断用户拥有的权限,能否访问目标资源

* @param request

* @param response

* @param chain

*/

@Override

publicvoiddoFilter(ServletRequestrequest,ServletResponseresponse,FilterChainchain)throwsIOException,ServletException{

HttpServletRequestreq=(HttpServletRequest)request;

HttpServletResponseres=(HttpServletResponse)response;

//获取客户端请求的资源是,去掉项目资源和无关后缀

Stringur=req.getRequestURI();

StringcontextPath=req.getContextPath();

Stringuri=ur.substring(contextPath.length());//去掉项目路径

if(uri.endsWith(".do")){//判断如果结尾是.do,则替换成""

uri=uri.replace(".do","");

       }

//从map里获取访问资源所需要的角色(权限)

StringhasRole=map.get(uri);

//如果客户端请求的页面在xml文件中没有配置资源路径,则直接放行

if(hasRole==null){

//不需要进行权限控制

System.out.println(uri+"不需要权限控制.直接放行");

chain.doFilter(req,res);

return;

       }

//获取当前用户拥有的角色(权限)

Useruser=(User)req.getSession().getAttribute("user");

//如果没有登录

if(user==null){

System.out.println(uri+"访问的用户没有登录");

res.sendRedirect(contextPath+"/login.html");

return;

       }

//已登录 得到当前用户拥有的权限

ListauthorityList=user.getAuthorityList();

//如果当前用户

if(authorityList==null||authorityList.size()==0){

res.getWriter().print(user.getUsername()+"用户无权限");

System.out.println(user.getUsername()+"用户没有权限");

return;

       }

booleancanAccess=false;//定义一个布尔变量  旗帜变量

//判断用户的权限,是否足够   用户拥有的角色(权限)里,是否包含目标资源所需要的任何一个角色(权限)

//用逗号进行分割  [ROLE_ADMIN],[ROLE_QUESTION_RECORDER]

String[]split=hasRole.split(",");

for(Strings:split){

//如果数据表中包含这个权限

if(authorityList.contains(s)){

canAccess=true;

break;

           }

       }

if(canAccess){

System.out.println(uri+"权限足够,放行");

chain.doFilter(req,res);

}else{

System.out.println(uri+"当前用户"+user.getUsername()+"权限不足,请切换用户");

res.getWriter().print("<<路径:"+uri+">>\n当前用户"+user.getUsername()+",权限不足,请切换用户");

       }

   }

过滤器配置(web.xml)

为了提高程序的可用性,解决硬编码问题,我们采用web.xml配置过滤器

/*

自定义框架-基于注解

创建注解

@Target(ElemenType.METHOD)          //元注解: 注解定义的位置

@Retention(RetentionPolicy.RUNTIME)//元注解: 注解存活的期限

public@interfacePreAuthorize{

Stringvalue();

}

在控制器方法上增加注解配置权限

    @PreAuthorize("QUESTION_REVIEW_UPDATE")

    @RequestMapping("/review/reviewQuestion")

publicvoidreviewQuestion(HttpServletRequestrequest,HttpServletResponseresponse)throwsIOException{

//......内容省略了.......重点看方法上增加的注解

  }

3.在过滤器中的int方法里增加代码

privateMapmap=newHashMap<>();

@Override

publicvoidinit(FilterConfigfilterConfig)throwsServletException{

//需要加载配置文件mm-security.xml 得到每个页面资源可以访问的角色

InputStreaminputStream=null;

try{

//通过过滤器的FilterConfig对象,可以得到web.xml里,配置的初始化参数

StringconfigLocation=filterConfig.getInitParameter("configLocation");

inputStream=this.getClass().getClassLoader().getResourceAsStream(configLocation);

//读取解析xml文件,得到里边的配置  dom4j

SAXReaderreader=newSAXReader();

Documentdocument=reader.read(inputStream);

/*  方法一

//获取xml文件里所有的security标签

//先找到根标签 ,再根据根标签找到里边的子标签

Element rootElement=document.getRootElement();

rootElement.element("security");*/

//方法二  用xpath表达式 //security,表示从xml文件里全文搜索security标签

Listsecurity=document.selectNodes("//security");

for(ElementsecurityElement:security){

//获取security标签的pattern属性值:资源路径

Stringpattern=securityElement.attributeValue("pattern");

//获取security标签的has_role属性值:哪些角色可以访问

Stringhas_role=securityElement.attributeValue("has_role");

//将读取的数据存储到Map集合,以资源路径作为键,以has_role的属性值作为值

map.put(pattern,has_role);

           }

//扫描Controller类中的方法  得到:资源 权限 是否可以访问

//先扫描xml文件中的package标签,得到里面的值

ElementscanEelement=(Element)document.selectSingleNode("//scan");

StringPackageName=scanEelement.attributeValue("package");

//扫描指定包下所有的类

List>classsFromPackage=    ClassScannerUtils.getClasssFromPackage(PackageName);

if(classsFromPackage!=null&&classsFromPackage.size()>0) {

//循环这个包下所有的类

for(ClassaClass:classsFromPackage) {

//先判断这个类是不是控制器

booleanannotationPresent=aClass.isAnnotationPresent(Controller.class);

if(annotationPresent){

//获取该类中的全部方法

Method[]methods=aClass.getMethods();

for(Methodmethod:methods){

//扫描类中所有方法,判断是否有@RequestMapping注解

booleanisRequestMapping=        method.isAnnotationPresent(PreAuthorize.class);

if(isRequestMapping){

//得到资源的访问路径

RequestMappingannotation=method.getAnnotation(RequestMapping.class);

StringmappingPath=annotation.value();

//得到资源的权限

PreAuthorizepreAuthorize=method.getAnnotation(PreAuthorize.class);

Stringvalue=preAuthorize.value();

//将这些数据保存到map中 以访问路径做键(@RequestMapping的值) 以@PreAuthorize的值为值

map.put(mappingPath,value);

                           }

                       }

                   }

               }

           }

}catch(Exceptione) {

e.printStackTrace();

}finally{

try{

if(inputStream!=null) {

inputStream.close();

               }

}catch(IOExceptione) {

e.printStackTrace();

           }

       }

   }

你可能感兴趣的:(一个zhuo'li自定义Spring 权限框架)