您的位置:首页 > 编程语言 > Java开发

springMVC与shiro集成

2015-06-24 11:21 671 查看
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{

@Autowired
UserReposity 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">
<bean
class="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, admin
test = 123, normal
[roles]
normal= *
admin = *
当然还可以有其它配置



源码下载:

springshiro
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: