Shiro整合
搭建好SSM项目
可参考SSM框架——详细整合教程(Spring+SpringMVC+MyBatis)
添加相关依赖
<!-- shiro相关的依赖 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>1.2.3</version>
</dependency>
在web.xml文件中注册shiro过滤器
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
id="WebApp_ID" version="3.1">
<display-name>SSM</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
<!-- 这里配置Spring配置文件的位置,param-name是固定的, param-value是文件位置 这个配置可以省略,如果省略, 系统默认去/WEB-INF/目录下查找applicationContext.xml作为Spring的配置文件 -->
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext-*.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<!-- 注册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:spring-mvc.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>
<!-- 配置中文的编码方式 -->
<filter>
<filter-name>characterEncodingFilter</filter-name>
<filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
<init-param>
<param-name>encoding</param-name>
<param-value>UTF-8</param-value>
</init-param>
<init-param>
<param-name>forceRequestEncoding</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>characterEncodingFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和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>shiro</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 防止静态资源文件被拦截 -->
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.jpg</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.png</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.css</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>default</servlet-name>
<url-pattern>*.js</url-pattern>
</servlet-mapping>
</web-app>
添加shiro的配置文件
注意shiro的配置可以添加在spring的配置文件中。但是为了便于管理我们再单独创建一个shiro的配置文件,里面的Schema还是spring的。
<?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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
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">
<!-- 定义凭证匹配器 -->
<bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"
id="credentialsMatcher">
<!-- 配置散列算法 -->
<property name="hashAlgorithmName" value="md5"/>
<!-- 配置散列次数 -->
<property name="hashIterations" value="1024"/>
</bean>
<!-- 注册自定义Realm -->
<bean class="com.yjn.realm.MyRealm" id="myRealm">
<!-- 配置凭证匹配器 -->
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>
<!-- 注册SecurityManager -->
<bean class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" id="securityManager">
<!-- 配置自定义Realm -->
<property name="realm" ref="myRealm"/>
</bean>
<!-- 注册ShiroFilterFactoryBean 注意id必须和web.xml中注册的targetBeanName的值一致 -->
<bean class="org.apache.shiro.spring.web.ShiroFilterFactoryBean" id="shiro">
<!-- 注册SecurityManager -->
<property name="securityManager" ref="securityManager"/>
<!-- 登录地址 如果用户请求的的地址是 login.do 那么会对该地址认证-->
<property name="loginUrl" value="/login.do"/>
<!-- 登录成功的跳转地址 -->
<property name="successUrl" value="/jsp/success.jsp"/>
<!-- 访问未授权的页面跳转的地址 -->
<property name="unauthorizedUrl" value="/jsp/refuse.jsp"/>
<!-- 设置 过滤器链 -->
<property name="filterChainDefinitions">
<value>
<!--加载顺序从上往下。
authc需要认证
anon可以匿名访问的资源
-->
/login.do=authc
/login.jsp=anon
/**=authc
</value>
</property>
</bean>
</beans>
认证部分
创建自定义的Realm类
/**
* 自定义的realm
*
*/
public class MyRealm extends AuthorizingRealm{
@Autowired
private UserService userService;
/**
* 认证的方法
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 获取登录的账号
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername();
System.out.println("登录提交的账号:"+username);
// 去数据库中查询
List<UserBean> list = userService.login(username);
if(list == null || list.size() != 1){
return null;
}
UserBean user = list.get(0);
return new SimpleAuthenticationInfo(user.getUsername()
, user.getPassword()
, new SimpleByteSource(user.getSalt())
, "abc");
}
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
}
LoginController测试
@Controller
public class LoginController {
/**
* 在shiro中
* 本方法在realm认证失败后会执行
* 指定认证失败跳转的页面
* @return
*/
@RequestMapping("/login.do")
public String login(Model model,HttpServletRequest request){
Object ex = request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
if(ex!= null) {
System.out.println(ex.toString()+"----------------");
}
if(UnknownAccountException.class.getName().equals(ex)) {
System.out.println("------账号不正确------->");
request.setAttribute("msg", "账号不正确");
return "redirect:/fail.jsp";
}else if(IncorrectCredentialsException.class.getName().equals(ex)) {
System.out.println("------密码不正确------->");
request.setAttribute("msg", "密码不正确");
return "redirect:/fail.jsp";
}
return "redirect:/success.jsp";
}
}
授权部分
在自定义的Realm类中添加授权处理的方法
/**
* 授权处理
* 形参中的获取的身份信息和 认证方法SimpleAuthenticationInfo的第一个参数有关
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) principals.getPrimaryPrincipal();
System.out.println("授权操作:"+userName);
// 根据认证信息去数据库中查询对应的角色和权限
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addRole("stu");
info.addRole("admin");
info.addStringPermission("user:create");
return info;
}
在SpringMVC的配置文件中开启Shiro注解
<!-- 开启Shiro注解 -->
<aop:config proxy-target-class="true"></aop:config>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean>
注解权限验证
@RequiresRoles("admin")//验证角色
@RequiresPermissions("user:update")//验证权限
@RequestMapping("/query2")
public String query2(){
System.out.println("----query2----");
return "/success.jsp";
}
指定没有权限访问的跳转地址
虽然配置了此设置,但是在使用注解的形式下,未授权的情况下还是不会跳转,此时我们需要在SpringMVC中添加对应的拦截器处理
<!-- shiro为集成springMvc 拦截异常 -->
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- 这里你可以根据需要定义N多个错误异常转发 -->
<prop key="org.apache.shiro.authz.UnauthorizedException">refuse.jsp</prop>
<prop key="org.apache.shiro.authz.UnauthenticatedException">login.jsp</prop>
<prop key="java.lang.IllegalArgumentException">fail.jsp</prop>
<prop key="java.lang.Exception">error.jsp</prop>
</props>
</property>
</bean>
jsp标签验证
引入标签库
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
标签验证
<h1>HOME页面</h1>
<h2>导航栏</h2>
<shiro:hasRole name="admin">
<a href="#">用户管理</a><br>
</shiro:hasRole>
<shiro:hasRole name="stu">
<a href="#">角色管理</a><br>
</shiro:hasRole>
<shiro:hasPermission name="user:create">
<a href="#">菜单管理</a><br>
</shiro:hasPermission>
<shiro:hasPermission name="dept:create">
<a href="#">部门管理</a><br>
</shiro:hasPermission>
<shiro:hasAnyRoles name="admin,a1,a2,a3">
<a href="#">xxxx</a><br>
</shiro:hasAnyRoles>
<shiro:authenticated>
<label>
【<shiro:principal ></shiro:principal>】
登录了。。。
</label><br>
</shiro:authenticated>
<shiro:guest>
<label>游客</label><br>
</shiro:guest>
<shiro:lacksRole name="stu">
<label>当前登录的账号没有stu1这个角色</label><br>
</shiro:lacksRole>
<shiro:user>
用户登录成功!
</shiro:user>
shiro标签说明
标签 | 说明 |
---|---|
<shiro:authenticated> | 表示已认证通过,只有已通过用户认证,而不是通过remenber me浏览,才能看到标签里的内容 |
<shiro:guest> | 只有没登录过,以游客的身份浏览才能看到标签里的内容 |
<shiro:hasRole name=""> | 表示拥有某一角色,name属性填角色名 |
<shiro:hasAnyRoles name=""> | 表示拥有多角色中任意一角色 |
<shiro:hasPermission name=""> | 表示拥有某一权限 |
<shiro:lacksRole name=""> | 表示不拥有某一角色 |
<shiro:lacksPermission name=""> | 表示不拥有某一权限 |
<shiro:notAuthenticated> | 表示没有通过认证 |
<shiro:principal> | 表示用户的身份 |
<shiro:user> | 表示已登录 |