springMVC与shiro集成

来源:互联网 发布:中华英才网 知乎 编辑:程序博客网 时间:2024/06/06 03:59


shiro可以跟springMVC很好的集成。

但是对于shiro集成struts2的资料比较少。

容易遇到注解失效等问题。

因为很多老的项目可能用的是Spring+ sturts框架。

如果我们使用shiro跟sturts集成的话 需要用到sturts的注解。

这样其实struts也失去了它跳转配置的便利。

所以  考虑了之后  还是觉得 使用springMVC框架与shiro集成。



我现在有一个spirngMVC的框架,在此基础上进行shiro的添加测试。


权限分析

用户分为两种用户normal,manager,有五个模块:结果查看模块,用户数据生成单选模块,用户数据生成批量模块,用户权限管理模块,操作日志查看模块。

normal用户:

结果查看模块resultlist,

用户数据生成单选模块parseResultUserlist,parseResultAdd

用户数据生成批量模块parseResultUserlistMulti,parseResultAddMulti

manager用户:

结果查看模块resultlist

用户数据生成单选模块parseResultUserlist,parseResultAdd

用户数据生成批量模块parseResultUserlistMulti,parseResultAddMulti

用户权限管理模块usermanage,

操作日志查看模块。loglist


新建User.class

根据shiro的模型 我们需要给User加上角色role和权限permission。因为我用的mongodb数据库是非关系型的数据库。我们把role和permission直接加在User对象里。

User.java

package com.test.web.support.shiro;import java.util.ArrayList;import java.util.List;import org.apache.shiro.authc.credential.DefaultPasswordService;import org.apache.shiro.authc.credential.PasswordService;import org.apache.shiro.crypto.hash.SimpleHash;import org.apache.shiro.util.ByteSource;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;import com.test.domain.entity.User;import com.test.domain.repository.UserReposity;public class UserAdd {public static void main(String[] args) { final String[] paths = new String[] {                  "src/main/resource/com/test/web/conf/mongodb/spring-mongodb.xml"};        final ApplicationContext context = new FileSystemXmlApplicationContext(                  paths); // ClassPathXmlApplicationContext          final UserReposity processor = (UserReposity) context                  .getBean("userReposity");  User user=new User();String username="test";String password="123";user.setUsername(username);    String encrypted =  new SimpleHash("MD5",password,null,1).toHex();    //这里的加密方式要与配置对应    //<property name="hashAlgorithmName" value="md5"/>指定hash算法为MD5;  无默认值,必须指定为MD5或者SHA-1等    //<property name="hashIterations" value="1"/>指定散列次数为1次;默认为1        // <property name="storedCredentialsHexEncoded" value="true"/>指定Hash散列值使用Hex加密存储。value="false"表明hash散列值用用Base64-encoded存储。默认为true     user.setPassword(encrypted);        List<String> permissionList=new ArrayList<String>();    List<String> roleList=new ArrayList<String>();    permissionList.add("parseResultAdd");    permissionList.add("parseResultAddMulti");       permissionList.add("resultlist");    roleList.add("normal");         user.setPermissionList(permissionList);    user.setRoleList(roleList);    processor.saveObject(user);}}


同时在数据库中中添加相关的user数据

我的mongodb数据添加两个用户如下:

{  "_id" : ObjectId("558915caa668aa7b08eb1197"),  "_class" : "com.test.domain.entity.User",  "username" : "admin",  "password" : "202cb962ac59075b964b07152d234b70",  "permissionList" : ["parseResultAdd", "parseResultAddMulti", "usermanage", "loglist", "resultlist"],  "roleList" : ["admin"]}{  "_id" : ObjectId("55891777a668e496191c6eb1"),  "_class" : "com.test.domain.entity.User",  "username" : "test",  "password" : "202cb962ac59075b964b07152d234b70",  "permissionList" : ["parseResultAdd", "parseResultAddMulti", "resultlist"],  "roleList" : ["normal"]}

"password" : "202cb962ac59075b964b07152d234b70"对应密码为123。


这里采用了shiro自带的加密方式。详情看下面的代码。


添加用户代码为:

package com.test.web.support.shiro;import java.util.ArrayList;import java.util.List;import org.apache.shiro.authc.credential.DefaultPasswordService;import org.apache.shiro.authc.credential.PasswordService;import org.apache.shiro.crypto.hash.SimpleHash;import org.apache.shiro.util.ByteSource;import org.springframework.context.ApplicationContext;import org.springframework.context.support.FileSystemXmlApplicationContext;import com.test.domain.entity.User;import com.test.domain.repository.UserReposity;public class UserAdd {public static void main(String[] args) {  final String[] paths = new String[] {                  "src/main/resource/com/test/web/conf/mongodb/spring-mongodb.xml"};        final ApplicationContext context = new FileSystemXmlApplicationContext(                  paths); // ClassPathXmlApplicationContext          final UserReposity processor = (UserReposity) context                  .getBean("userReposity");  User user=new User();String username="admin";String password="123";user.setUsername(username);    String encrypted =  new SimpleHash("MD5",password,null,1).toHex();    //这里的加密方式要与配置对应    //<property name="hashAlgorithmName" value="md5"/>指定hash算法为MD5;  无默认值,必须指定为MD5或者SHA-1等    //<property name="hashIterations" value="1"/>指定散列次数为1次;默认为1        // <property name="storedCredentialsHexEncoded" value="true"/>指定Hash散列值使用Hex加密存储。value="false"表明hash散列值用用Base64-encoded存储。默认为true     user.setPassword(encrypted);        List<String> permissionList=new ArrayList<String>();    List<String> roleList=new ArrayList<String>();    permissionList.add("parseResultAdd");    permissionList.add("parseResultAddMulti");    permissionList.add("usermanage");    permissionList.add("loglist");    permissionList.add("resultlist");         roleList.add("admin");    user.setPermissionList(permissionList);    user.setRoleList(roleList);    processor.saveObject(user);}}
   

String encrypted =  new SimpleHash("MD5",password,null,1).toHex();

使用shiro注册增加用户时的加密方式要与自己的设置想匹配。

spring-shiro.xml中配置为:

 <bean id="mongoRealm" class="com.test.web.support.shiro.MyShiro"><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"></property></bean></property></bean> 
验证时为:





添加后如图所示:





导入jar

因为我们的是maven工程,所以把shiro相关的包写入pom.xml文件。

在pom.xml中添加

 <!--Apache Shiro所需的jar包-->        <dependency>          <groupId>org.apache.shiro</groupId>          <artifactId>shiro-core</artifactId>          <version>1.2.2</version>        </dependency>        <dependency>          <groupId>org.apache.shiro</groupId>          <artifactId>shiro-web</artifactId>          <version>1.2.2</version>        </dependency>        <dependency>          <groupId>org.apache.shiro</groupId>          <artifactId>shiro-spring</artifactId>          <version>1.2.2</version>        </dependency>   

完整版的pom.xml太长,这里就不给出了,可下载源码查看


配置web.xml

在web.xml里添加shiro 的配置

shiro的filter应该放在struts2的 filter的上面

 <!-- Shiro配置 -->      <filter>        <filter-name>shiroFilter</filter-name>        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>      </filter>      <filter-mapping>        <filter-name>shiroFilter</filter-name>        <url-pattern>/*</url-pattern>      </filter-mapping>  

完整版web.xml

<?xml version="1.0" encoding="UTF-8"?><web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"version="3.0"><filter><filter-name>encodingFilter</filter-name><filter-class>com.test.web.servlet.filter.EncodingFilter</filter-class></filter><filter><filter-name>shiroFilter</filter-name><filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class><init-param><param-name>targetFilterLifecycle</param-name><param-value>true</param-value></init-param></filter><filter-mapping><filter-name>encodingFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><filter-mapping><filter-name>shiroFilter</filter-name><url-pattern>/*</url-pattern></filter-mapping><servlet><servlet-name>springMVC</servlet-name><servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class><init-param><param-name>contextConfigLocation</param-name><param-value>classpath:spring-web.xml</param-value></init-param><load-on-startup>1</load-on-startup></servlet><servlet-mapping><servlet-name>springMVC</servlet-name><url-pattern>/</url-pattern></servlet-mapping><listener><listener-class>org.springframework.web.context.ContextLoaderListener</listener-class></listener><context-param><param-name>contextConfigLocation</param-name><param-value>            classpath:spring-web.xml        </param-value></context-param><welcome-file-list><welcome-file></welcome-file></welcome-file-list><session-config><cookie-config><name>_sid</name></cookie-config><tracking-mode>COOKIE</tracking-mode></session-config><error-page><error-code>404</error-code><location>/404</location></error-page><error-page><exception-type>javax.servlet.ServletException</exception-type><location>/error</location></error-page><jsp-config><jsp-property-group><url-pattern>*.jsp</url-pattern><page-encoding>UTF-8</page-encoding><scripting-invalid>false</scripting-invalid></jsp-property-group></jsp-config></web-app>


建立dbRelm

主要是扩展AuthorizingRealm, 实现在数据库中查询是否有该帐号密码,实现验证。

我新建一个MyShiro的class

MyShiro.java

package com.test.web.support.shiro;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.AuthenticationInfo;import org.apache.shiro.authc.AuthenticationToken;import org.apache.shiro.authc.SimpleAuthenticationInfo;import org.apache.shiro.authc.UsernamePasswordToken;import org.apache.shiro.authz.AuthorizationInfo;import org.apache.shiro.authz.SimpleAuthorizationInfo;import org.apache.shiro.realm.AuthorizingRealm;import org.apache.shiro.subject.PrincipalCollection;import org.springframework.beans.factory.annotation.Autowired;import com.test.domain.entity.User;import com.test.domain.repository.UserReposity;public class MyShiro extends AuthorizingRealm{  @AutowiredUserReposity userReposity;  /**      * 权限认证      */      @Override      protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {           //获取登录时输入的用户名          String loginName=(String) principalCollection.fromRealm(getName()).iterator().next();          //到数据库查是否有此对象          User user=userReposity.findByName(loginName);          if(user!=null){              //权限信息对象info,用来存放查出的用户的所有的角色(role)及权限(permission)              SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();              //用户的角色集合              info.addRoles(user.getRoleList());              //用户的角色对应的所有权限,如果只使用角色定义访问权限,下面的一行可以不要                info.addStringPermissions(user.getPermissionList());                         return info;          }          return null;      }        /**      * 登录认证;      */      @Override      protected AuthenticationInfo doGetAuthenticationInfo(              AuthenticationToken authenticationToken) throws AuthenticationException {          //UsernamePasswordToken对象用来存放提交的登录信息          UsernamePasswordToken token=(UsernamePasswordToken) authenticationToken;          //查出是否有此用户          User user=userReposity.findByName(token.getUsername());          if(user!=null){              //若存在,将此用户存放到登录认证info中              return new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());          }          return null;      }}


同时还应配置mongodb的访问xml和userReposity的bean定义,这里不给出了,详情可下载源码

主要有两部分 

一是对数据库具体访问的接口实现 


二是 spring-mongodb.xml 

<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"xmlns:mongo="http://www.springframework.org/schema/data/mongo"xmlns:repository="http://www.springframework.org/schema/data/repository"xsi:schemaLocation="        http://www.springframework.org/schema/beans        http://www.springframework.org/schema/beans/spring-beans-3.2.xsd        http://www.springframework.org/schema/data/mongo        http://www.springframework.org/schema/data/mongo/spring-mongo-1.5.xsd        ">       <bean id="userReposity" class="com.test.domain.repository.impl.UserReposityImpl"parent="mongoTemplate"></bean><bean id="mongoTemplate" class="org.springframework.data.mongodb.core.MongoTemplate">               <constructor-arg name="mongo" ref="mongo" />        <constructor-arg name="databaseName" value="shiro_test"/>     </bean>      <bean id="mongo" class="org.springframework.data.mongodb.core.MongoFactoryBean">          <property name="host" value="127.0.0.1"/>          <property name="port" value="27017"/>       </bean> </beans>




新建用于登录,登出,权限跳转的控制HomeController 

HomeController.java

package com.test.web.controller;import org.apache.shiro.SecurityUtils;import org.apache.shiro.authc.AuthenticationException;import org.apache.shiro.authc.UsernamePasswordToken;import org.springframework.ui.Model;import org.springframework.validation.BindingResult;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.servlet.mvc.support.RedirectAttributes;import com.test.domain.entity.User;public class HomeController {   @RequestMapping(value="/login",method=RequestMethod.GET)      public String loginForm(Model model){          model.addAttribute("user", new User());          return "/login";      }            @RequestMapping(value="/login",method=RequestMethod.POST)      public String login(User user,BindingResult bindingResult,RedirectAttributes redirectAttributes){          try {              if(bindingResult.hasErrors()){                  return "/login";              }              //使用权限工具进行用户登录,登录成功后跳到shiro配置的successUrl中,与下面的return没什么关系!              SecurityUtils.getSubject().login(new UsernamePasswordToken(user.getUsername(), user.getPassword()));              return "/home";          } catch (AuthenticationException e) {              redirectAttributes.addFlashAttribute("message","用户名或密码错误");              return "redirect:/login";          }      }            @RequestMapping(value="/logout",method=RequestMethod.GET)        public String logout(RedirectAttributes redirectAttributes ){           //使用权限管理工具进行用户的退出,跳出登录,给出提示信息          SecurityUtils.getSubject().logout();            redirectAttributes.addFlashAttribute("message", "您已安全退出");            return "redirect:/login";      }             @RequestMapping("/403")      public String unauthorizedRole(){          return "/403";      }  }


新建登录显示页面

三个页面放在views文件夹中 login.jsp,home.jsp,403.jsp

login.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <html>    <head>      <title>My JSP 'MyJsp.jsp' starting page</title>    </head>        <body>      <h1>登录页面----${message }</h1>         <form:form action="/login" commandName="user" method="post">          用户名:<form:input path="username"/> <form:errors path="username" cssClass="error"/> <br/>          密   码:<form:password path="password"/> <form:errors path="password" cssClass="error" /> <br/>          <form:button name="button">submit</form:button>      </form:form>    </body>  </html>  


页面上的commandName的user需要与HomeController中

   @RequestMapping(value="/login",method=RequestMethod.GET)  
   public String loginForm(Model model){  
       model.addAttribute("user", new User());  
       return "/login";  
   }  

里的user对应。属性名对应。


home.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>  <%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <html>    <head>      <title>用户列表</title>    </head>    <body>      <h1>${message }</h1>      <h1>用户列表--<a href="/user/add">添加用户</a>---<a href="./logout">退出登录</a>    </h1>     <h2>权限列表----<shiro:principal/>-当前登录用户名  <br></h2>      <shiro:authenticated>用户已经登录显示此内容<br></shiro:authenticated>         <shiro:hasRole name="admin">admin角色登录显示此内容<br></shiro:hasRole>       <shiro:hasRole name="normal">normal角色登录显示此内容<br></shiro:hasRole>    <shiro:hasAnyRoles name="normal,admin">**normal or admin 角色用户登录显示此内容**<br></shiro:hasAnyRoles>         <shiro:hasPermission name="loglist">loglist权限用户显示此内容<br></shiro:hasPermission>         <shiro:lacksPermission name="loglist"> 不具有loglist权限的用户显示此内容 <br></shiro:lacksPermission>          <script type="text/javascript" src="http://cdn.staticfile.org/jquery/1.9.1/jquery.min.js"></script>      <script>          $(function(){              $(".del").click(function(){                  var id=$(this).attr("ref");                  $.ajax({                      type:"delete",                      url:"/user/del/"+id,                      success:function(e){                                                }                  });              });          });      </script>    </body>  </html>  


403.jsp

<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>  <%@ taglib prefix="form" uri="http://www.springframework.org/tags/form" %>  <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">  <html>    <head>      <title>权限错误</title>    </head>        <body>      <h1>对不起,您没有权限请求此连接!</h1>    </body>  </html>  




在Spring中配置

spring-shiro.xml

<?xml version="1.0" encoding="UTF-8"?><!-- ~ Licensed to the Apache Software Foundation (ASF) under one ~ or more contributor license agreements. See the NOTICE file ~ distributed with this work for additional information ~ regarding copyright ownership. The ASF licenses this file ~ to you under the Apache License, Version 2.0 (the ~ "License"); you may not use this file except in compliance ~ with the License. You may obtain a copy of the License at ~ ~ http://www.apache.org/licenses/LICENSE-2.0 ~ ~ Unless required by applicable law or agreed to in writing, ~ software distributed under the License is distributed on an ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ~ KIND, either express or implied. See the License for the ~ specific language governing permissions and limitations ~ under the License. --><beans xmlns="http://www.springframework.org/schema/beans"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.0.xsd"><!--<bean id="iniRealm" class="org.apache.shiro.realm.text.IniRealm"><constructor-arg name="resourcePath"value="classpath:com/test/web/conf/shiro/shiro.ini"></constructor-arg></bean>--> <bean id="mongoRealm" class="com.test.web.support.shiro.MyShiro"><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"></property></bean></property></bean> <!-- securityManager --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="rememberMeManager"><bean class="org.apache.shiro.web.mgt.CookieRememberMeManager"><property name="cookie"><bean class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg name="name" value="RememberMe" /><property name="maxAge" value="604800" /></bean></property></bean></property><!-- <property name="realm" ref="iniRealm" /> --><property name="realm" ref="mongoRealm" /></bean><!-- shiroFilter --><bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"><property name="securityManager" ref="securityManager" /><property name="loginUrl" value="/login" /><property name="successUrl" value="/" /><property name="unauthorizedUrl" value="/login" /><property name="filters"><map><entry key="authc"><beanclass="com.test.web.support.shiro.AjaxCompatibleAuthenticationFilter"></bean></entry></map></property><property name="filterChainDefinitions"><value>/login = anon<!-- anon表示此地址不需要任何权限即可访问 -->                 <!--  /static/**=anon  -->                 <!-- perms[user:query]表示访问此连接需要权限为user:query的用户 -->                 <!--  /user=perms[user:query]   -->                <!-- roles[manager]表示访问此连接需要用户的角色为manager -->                 <!--  /user/add=roles[manager]   -->               <!--  /user/del/**=roles[admin]   -->               <!--  /user/edit/**=roles[manager]   -->                <!--所有的请求(除去配置的静态资源请求或请求地址为anon的请求)都要通过登录验证,如果未登录则跳到/login-->                   <!--  /** = authc  --> </value></property></bean></beans>

这里对页面的访问权限可以相应调节。



结果展示

启动后分别用admin和test账户登录可以看到根据角色和权限已经能显示不同的内容







ps:启用ini配置

realm如果不想用数据库,也可以用文本形式配置,如下

spring-shiro.xml中注释mongoRealm,启用iniRealm

<bean id="iniRealm" class="org.apache.shiro.realm.text.IniRealm"><constructor-arg name="resourcePath"value="classpath:com/test/web/conf/shiro/shiro.ini"></constructor-arg></bean><!-- <bean id="mongoRealm" class="com.test.web.support.shiro.MyShiro"><property name="credentialsMatcher"><bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"><property name="hashAlgorithmName" value="MD5"></property></bean></property></bean> --><!-- securityManager --><bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"><property name="rememberMeManager"><bean class="org.apache.shiro.web.mgt.CookieRememberMeManager"><property name="cookie"><bean class="org.apache.shiro.web.servlet.SimpleCookie"><constructor-arg name="name" value="RememberMe" /><property name="maxAge" value="604800" /></bean></property></bean></property> <property name="realm" ref="iniRealm" /> <!--<property name="realm" ref="mongoRealm" />--></bean>

新建shiro.ini



shiro.ini 里是帐号密码和角色

[users]admin = 123, admintest = 123, normal[roles]normal= *admin = *
当然还可以有其它配置






源码下载:

springshiro




1 1
原创粉丝点击