本章节主要介绍Shiro+SpringMVC+oracle+maven整合,并实现shiro的身份验证和授权。
-
建表并插入数据
--1、用户表
CREATETABLEusers_Table(
user_id number(10)primarykey,
user_name varchar2(64) ,
passwordvarchar2(48)
) ;
createsequence users_seq;
insertintousers_Tablevalues(users_seq.nextval,'admin','123456');
insertinto users_Tablevalues(users_seq.nextval,'afeng','qw123456');
insertinto users_Tablevalues(users_seq.nextval,'czf','we2133');
select *from users_Table;
--2、角色表
CREATETABLE roles_Table (
role_id number(10)primarykey,
role_name varchar2(64)
)
createsequence roles_seq;
insertinto roles_Tablevalues(roles_seq.nextval,'admin');
insertinto roles_Tablevalues(roles_seq.nextval,'manager');
insertinto roles_Tablevalues(roles_seq.nextval,'programmer');
select *from roles_Table;
--3、权限表
CREATETABLE permissions_Table (
permission_id number(10)primarykey,
permission_namevarchar2(64)
);
createsequence permissions_seq;
insertinto permissions_Tablevalues(permissions_seq.nextval,'add');
insertinto permissions_Tablevalues(permissions_seq.nextval,'update');
insertinto permissions_Tablevalues(permissions_seq.nextval,'delete');
insertinto permissions_Tablevalues(permissions_seq.nextval,'query');
insertinto permissions_Tablevalues(permissions_seq.nextval,'create_user');
select *from permissions_Table;
--4、用户和角色的关系表
CREATETABLE user_role_table(
idnumber(10)primarykey,
user_id number(10) ,
role_id number(10)
)
dropsequence user_role_seq;
createsequence user_role_seq;
insertinto user_role_tablevalues(user_role_seq.nextval,1,1);
insertinto user_role_tablevalues(user_role_seq.nextval,2,2);
insertinto user_role_tablevalues(user_role_seq.nextval,3,3);
select *from user_role_table;
--5、角色和权限的关系
CREATETABLErole_permissions_table (
idnumber(10)primarykey,
permission_id number(10),
role_id number(10)
);
dropsequencerole_permission_seq;
createsequencerole_permission_seq;
insertinto role_permissions_tablevalues(role_permission_seq.nextval,1,1);
insertinto role_permissions_tablevalues(role_permission_seq.nextval,1,2);
insertinto role_permissions_tablevalues(role_permission_seq.nextval,1,3);
insertinto role_permissions_tablevalues(role_permission_seq.nextval,2,1);
select *from role_permissions_table;
--6、常见语句
--1、根据用户名查询密码
SELECTpasswordFROM users_TableWHERE user_name='admin';
--2、根据用户名查询角色
SELECT role_namefromuser_role_tableleftjoin roles_Tableusing(role_id)leftjoin
users_Tableusing(user_id)WHERE user_name ='afeng';
--3、根据角色查询权限
SELECT permission_nameFROMrole_permissions_tableleftjoin roles_Tableusing(role_id)left
joinpermissions_Tableusing(permission_id)WHERErole_name ='admin';
-
整体架构
见上图
-
加载依赖
需要注意的是,加载shiro-spring包时,shiro-core等jar包也会加载,因为shiro-core是shiro-spring的必须的依赖包。
另外,maven中央服务器不在提供oracle10g的驱动包的下载,有两种解决方案,一种是下载oracle10g的驱动包,并放在本地maven仓库,另外一种改成更高版本的驱动包。
<!-- 1、shiro-spring -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<!-- 2、Spring MVC -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- 3、spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>4.3.9.RELEASE</version>
</dependency>
<!-- 4、oracle -->
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>10.2.0.4.0</version>
</dependency>
-
配置文件
-
web.xml
<!-- 1、配置Shiro Filter -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!--设置true由servlet容器控制filter的生命周期 -->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!--设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean-->
<init-param>
<param-name>targetBeanName</param-name>
<param-value>shiroFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--2、加载shiro的配置文件-->
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:Shiro.xml</param-value>
</context-param>
<!--3、加载springmvc的配置文件-->
<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:SpringMVC.xml</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<!-- 4、配置错误,当错误代码为401时,导向401.jsp -->
<error-page>
<error-code>401</error-code>
<location>/401.jsp</location>
</error-page>
-
SpringMVC.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd">
<mvc:annotation-driven></mvc:annotation-driven>
<context:component-scanbase-package="cn.com.bochy"></context:component-scan>
<beanid="ViewResolver"class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<propertyname="prefix"value="/WEB-INF/view/"></property>
<propertyname="suffix"value=".jsp"></property>
</bean>
</beans>
-
Shiro.xml
<?xmlversion="1.0"encoding="UTF-8"?>
<beansxmlns="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.xsd">
<!-- 1、配置数据源:dataSource -->
<beanid="ds"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<propertyname="driverClassName"value="oracle.jdbc.driver.OracleDriver"/>
<propertyname="url"value="jdbc:oracle:thin:@localhost:1521:orcl"/>
<propertyname="username"value="system"/>
<propertyname="password"value="orcl"/>
</bean>
<!-- 2、Shiro生命周期处理器:保证实现了Shiro内部lifecycle函数的bean执行,
LifecycleBeanPostProcessor用于在实现了Initializable接口的Shiro bean初始化时调用Initializable接口回调,
在实现了Destroyable接口的Shiro bean销毁时调用Destroyable接口回调。如UserRealm就实现了Initializable,
而DefaultSecurityManager实现了Destroyable -->
<beanid="lifecycleBeanPostProcessor"
class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>
<!-- 3、缓存管理:用户授权信息Cache,shiro自定的本机内存实现的cacheManager类,缓存在本机内存,不支持集群,非必须-->
<!-- <bean id="cacheManager"class="org.apache.shiro.cache.MemoryConstrainedCacheManager"></bean> -->
<!--4、使用Shiro自带的JdbcRealm类 ,指定存储用户、角色、权限许可的数据源及相关查询语句 -->
<beanid="jdbcRealm"class="org.apache.shiro.realm.jdbc.JdbcRealm">
<propertyname="permissionsLookupEnabled"value="true"></property>
<propertyname="dataSource"ref="ds"></property>
<propertyname="authenticationQuery"
value="SELECTpassword FROM users_Table WHERE user_name = ?"></property>
<propertyname="userRolesQuery"
value="SELECTrole_name from user_role_table left join roles_Table using(role_id) left join
users_Tableusing(user_id) WHERE user_name = ?"></property>
<propertyname="permissionsQuery"
value="SELECTpermission_name FROM role_permissions_table left join roles_Tableusing(role_id) left
join permissions_Tableusing(permission_id) WHERE role_name = ?"></property>
</bean>
<!-- 5、Shiro安全管理器 -->
<beanid="securityManager"class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<propertyname="realm"ref="jdbcRealm"></property>
<!-- <property name="cacheManager" ref="cacheManager"></property>-->
</bean>
<!--
Shiro主过滤器本身功能十分强大,其强大之处就在于它支持任何基于URL路径表达式的、自定义的过滤器的执行
Web应用中,Shiro可控制的Web请求必须经过Shiro主过滤器的拦截,Shiro对基于Spring的Web应用提供了完美的支持
-->
<beanid="shiroFilter"class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--Shiro的核心安全接口,这个属性是必须的 -->
<propertyname="securityManager"ref="securityManager"></property>
<!--要求登录时的链接(登录页面地址),非必须的属性,默认会自动寻找Web工程根目录下的"/login.jsp"页面 -->
<propertyname="loginUrl"value="/login.do"></property>
<!--登录成功后要跳转的连接(本例中此属性用不到,因为登录成功后的处理逻辑在LoginController里硬编码) -->
<!-- <property name="successUrl" value="/"></property> -->
<!--用户访问未对其授权的资源时,所显示的连接 -->
<propertyname="filterChainDefinitions">
<value>
/security/**=anon <!--访问security下的资源,匿名,无需验证 -->
/admin/** =authc,roles[admin]<!--访问admin下的资源,需要身份验证,且角色必须为admin -->
/edit/**=authc,roles[admin],perms[update]<!--访问edit下的资源,需要身份验证,且角色必须为admin且拥有update权限 -->
/manager.do=authc,perms[manager]<!--访问manager.do,需要身份验证,且必须拥有manager权限 -->
</value>
</property>
</bean>
</beans>
-
ShiroSpringMVCController.java
package cn.com.bochy.controller;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.DisabledAccountException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.UnauthorizedException;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
publicclass ShiroSpringMVCController {
@RequestMapping("/login")
public String sayHello(){
return"security/login";
}
@RequestMapping("/manager")
public String sayManager(){
System.out.println("manager...");
return"manager/query";
}
@RequestMapping("/main")
public String main(){
return"main";
}
@RequestMapping(value ="/dologin")
public String doLogin(HttpServletRequestrequest, Model model) {
Subject subject =SecurityUtils.getSubject();
String msg ="";
String userName =request.getParameter("userName");
System.out.println(userName);
String password = request.getParameter("password");
System.out.println(password);
UsernamePasswordTokentoken =new UsernamePasswordToken(userName, password);
token.setRememberMe(true);
try {
subject.login(token);
System.out.println(subject.hasRole("admin"));
System.out.println(subject.hasRole("manager"));
System.out.println(subject.isPermitted("add"));
System.out.println(subject.isPermitted("query"));
if(subject.isAuthenticated()) {
return"redirect:/main.do";
} else {
return"security/login";
}
} catch(IncorrectCredentialsException e) {
msg = "登录密码错误. Password for account " +token.getPrincipal() +" wasincorrect.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch(ExcessiveAttemptsException e) {
msg = "登录失败次数过多";
model.addAttribute("message", msg);
System.out.println(msg);
} catch(LockedAccountException e) {
msg = "帐号已被锁定. The account for username " +token.getPrincipal() +" waslocked.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch (DisabledAccountExceptione) {
msg = "帐号已被禁用. The account for username " +token.getPrincipal() +" wasdisabled.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch(ExpiredCredentialsException e) {
msg = "帐号已过期. the account for username " +token.getPrincipal() +" was expired.";
model.addAttribute("message", msg);
System.out.println(msg);
} catch(UnknownAccountException e) {
msg = "帐号不存在. There is no user with username of " + token.getPrincipal();
model.addAttribute("message", msg);
System.out.println(msg);
} catch(UnauthorizedException e) {
msg = "您没有得到相应的授权!" +e.getMessage();
model.addAttribute("message", msg);
System.out.println(msg);
}
return"security/login";
}
@RequestMapping("/edit/query")
publicString editDemo(){
return"edit/query";
}
}
-
页面制作
1、index.jsp
<%@pagelanguage="java"import="java.util.*"pageEncoding="utf-8"%>
<%
String path =request.getContextPath();
String basePath =request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPEHTML>
<html>
<head>
<basehref="<%=basePath%>">
<title>starting page</title>
</head>
<body>
<ahref="login.do">login</a>
</body>
</html>
2、login.jsp
<%@pagelanguage="java"contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPEhtml>
<html>
<head>
<metahttp-equiv="Content-Type"content="text/html; charset=UTF-8">
<title>Shiro和SpringMVC整合</title>
</head>
<body>
<h1>Shiro和SpringMVC整合-登录页面</h1>
<form action="dologin.do"method="post">
<table>
<tr>
<td>请输入用户名:</td>
<td><inputtype="text"name="userName"/></td>
</tr>
<tr>
<td>请输入密码:</td>
<td><inputtype="password"name="password"/></td>
</tr>
<tr>
<td></td>
<td><inputtype="submit"value="登录"/></td>
</tr>
</table>
</form>
<%--用于输入后台返回的验证错误信息 --%>
<p>${message}</p>
</body>
</html>
其他页面省略。
-
执行结果:
-
无需认证,即可访问login.jsp
-
需要认证,才可以访问如下资源
http://localhost:8080/14shiroSpringMVC/edit/query.do
http://localhost:8080/14shiroSpringMVC/admin/1.jsp
http://localhost:8080/14shiroSpringMVC/manager.do
详情请看shiro的配置文件:
/security/**=anon <!--访问security下的资源,匿名,无需验证 -->
/admin/** =authc,roles[admin]<!--访问admin下的资源,需要身份验证,且角色必须为admin -->
/edit/**=authc,roles[admin],perms[update]<!--访问edit下的资源,需要身份验证,且角色必须为admin且拥有update权限 -->
/manager.do=authc,perms[manager]<!--访问manager.do,需要身份验证,且必须拥有manager权限 -->