1.首先整合SSM框架,起码项目要能跑起来
以前整合好的ssm框架
springmvc-config.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd
http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 注解驱动 -->
<mvc:annotation-driven/>
<!-- 静态资源路径 -->
<mvc:default-servlet-handler/>
<!-- 扫描controller包 -->
<context:component-scan base-package="com.kuang.controller"/>
<!-- 视图解析器 -->
<bean id="internalResourceViewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/jsp/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
spring-dao.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 导入本地jdbc配置 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- DataSource:使用spring数据源替换mybatis的配置 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- sqlSessionFactory -->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!-- 配置数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 配置mybatis配置文件 -->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<!-- 自动扫描Mapper -->
<property name="mapperLocations" value="classpath:com/kuang/mapper/*.xml"/>
</bean>
<!-- 自动生成userMapper实现类 -->
<bean id="mapperScannerConfigurer" class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.kuang.mapper"/>
</bean>
</beans>
spring-service.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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 扫描service包 -->
<context:component-scan base-package="com.kuang.service"/>
<import resource="classpath:spring-dao.xml"/>
<!-- 声明式事务 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
application.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<import resource="classpath:springmvc-config.xml"/>
<import resource="classpath:spring-dao.xml"/>
<import resource="classpath:spring-service.xml"/>
</beans>
jdbc.properties
jdbc.driver = com.mysql.cj.jdbc.Driver
jdbc.url = jdbc:mysql://localhost:3306/student?characterEncoding=utf8
jdbc.username = root
jdbc.password = 1511
2.新建spring-shiro配置文件
<?xml version="1.0" encoding="UTF-8"?>
<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-4.1.xsd
"
default-lazy-init="true">
<!--1. 配置securityManager安全管理器 -->
<!--
SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;
且它管理着所有Subject;可以看出它是Shiro 的核心,它负责与后边介绍的其他组件进行交互
-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="shiroDbRealm" />
</bean>
<!--2. 配置 CacheManager. 2.1需要加入 ehcache 的 jar 包及配置文件. -->
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager"> </bean>
<!--3.配置realm 自定义的Realm-->
<!--
Shiro 从从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,
那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;
也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;
可以把Realm看成DataSource , 即安全数据源
-->
<bean id="shiroDbRealm" class="com.kuang.auth.realm.UserRealm"></bean>
<!--4.配置lifecycleBeanPostProcessor,可以自动调用spring ioc 容器中的shiro bean 的生命周期方法 -->
<!-- 开启Shiro注解的Spring配置方式的beans。在lifecycleBeanPostProcessor之后运行 -->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />
<!--5. 启用 IOC 容器中使用 shiro 的注解. 但必须在配置了 LifecycleBeanPostProcessor 之后才可以使用. -->
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
depends-on="lifecycleBeanPostProcessor">
<property name="proxyTargetClass" value="true" />
</bean>
<!-- Shiro Filter id值和web.xml文件配置的过滤器名称相同 -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<!-- 登录页面 -->
<!--<property name="loginUrl" value="/login.jsp" />-->
<!-- 登录成功页面 已经在登录Controller中配置 所以这里就注释了-->
<!--<property name="successUrl" value="/WEB-INF/views/home.jsp"/>-->
<!-- 没有权限的页面 -->
<property name="unauthorizedUrl" value="/user/error"/>
<!--
配置哪些页面需要受保护.
以及访问这些页面需要的权限.
1). anon 可以被匿名访问
2). authc 必须认证(即登录)后才可能访问的页面.
3). logout 登出.
4). roles 角色过滤器
-->
<property name="filterChainDefinitions">
<value>
<!-- 登录可匿名访问 -->
<!-- 注意:路径的匹配顺序从上往下,返回第一个匹配到的配置
比如当把 /** = authc 放在最上面,
那无论下面配置了什么路径 都需要认证,
-->
/index = anon
/ = anon
/user/login = anon
<!-- 其他的需要授权访问authc -->
/user/add = perms[user:add]
/user/update = perms[user:update]
<!-- logout只需在这里配置一个路径即可完成注销功能,即使控制器没有写 -->
/logout = logout
/** = authc
</value>
</property>
</bean>
<!-- 开启Shiro注解的Spring配置方式的beans。在lifecycleBeanPostProcessor之后运行 -->
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
<!-- shiro为集成spring -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- 无权限跳转到登陆页,可自行定义 -->
<prop key="org.apache.shiro.authz.UnauthorizedException">error/error</prop>
</props>
</property>
</bean>
</beans>
application.xml配置文件中也要导入
<import resource="classpath:spring-shiro.xml"/>
3.web.xml中页面添加shiro
<!-- shiro 安全过滤器 -->
<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>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
web.xml完整代码
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0">
<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-config.xml
classpath:spring-shiro.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>encoding</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>
</filter>
<filter-mapping>
<filter-name>encoding</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- shiro 安全过滤器 -->
<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>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
4.创建UserRealm类,并继承AuthorizingRealm类
package com.kuang.auth.realm;
import com.kuang.pojo.User;
import com.kuang.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import java.util.Arrays;
//UserRealm继承AuthorizingRealm类
public class UserRealm extends AuthorizingRealm{
@Autowired
private UserService userMapper;
/**
* 授权
* 在这里可以配置权限方面的信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//获取当前登录用户
Subject subject = SecurityUtils.getSubject();
//获取getPrincipal里存储的信息
User user = (User) subject.getPrincipal();
//添加权限(Collection权限集合)
info.addStringPermissions(Arrays.asList(user.getPerms().split(",")));
//添加角色(Collection权限集合)
//info.addRoles();
return info;
}
/**
* 认证
* 在这里可以将用户传进来的数据与数据库的用户名密码进行匹配
* 还能存储正确的User对象(principal)
* new SimpleAuthenticationInfo(user(principal), user.getPassword(), user.getUsername());
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
String username = usernamePasswordToken.getUsername();
String password = String.valueOf(usernamePasswordToken.getPassword());
User user = userMapper.findByUsername(username);
if(user == null) {
throw new AccountException("账号或密码错误");
}
if(!password.equals(user.getPassword())){
throw new AccountException("账号或密码错误");
}
SecurityUtils.getSubject().getSession().setAttribute("userInfo",user);
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(
user, user.getPassword(), user.getUsername());
return simpleAuthenticationInfo;
}
}
5.编写主页,登录等jsp页面
建好的页面,除了基本功能什么都没有
6.jsp中引入shiro标签,并使用
想要在jsp页面使用shiro标签必须导入标签库
<%@taglib prefix=“shiro” uri=“http://shiro.apache.org/tags” %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%-- 导入shiro + Jsp整合权限控制 --%>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
<title>主页</title>
</head>
<%--<c:if test="${pageContext.session.getAttribute('userInfo')}">
<a href="${pageContext.request.contextPath}/user/logout">注销</a>
</c:if>--%>
<%-- 判断是否已认证 --%>
<shiro:authenticated>
<%-- 取出储存的user对象中的username --%>
<shiro:principal property="username">
<h3>欢迎回来 <a href="#">${username}</a></h3>
</shiro:principal>
<a href="${pageContext.request.contextPath}/logout">注销</a>
</shiro:authenticated>
<%-- 判断是否没有认证 --%>
<shiro:notAuthenticated>
<a href="${pageContext.request.contextPath}/user/toLogin">登录</a>
</shiro:notAuthenticated>
<hr>
<%-- 判断是否拥有某个权限 --%>
<shiro:hasPermission name="user:add">
<a href="${pageContext.request.contextPath}/user/add">add</a>
</shiro:hasPermission>
<shiro:hasPermission name="user:update">
<a href="${pageContext.request.contextPath}/user/update">update</a>
</shiro:hasPermission>
</body>
</html>
7.测试shiro是否正常使用
主页,只显示当前用户拥有的权限,未登录当然什么都没有
登录页面
登录成功后显示当前权限
上图显示admin用户只拥有add权限,即使输入update也无法访问
测试成功
注:配上shiro jsp页面使用标签说明
下面来讲解具体的标签用法。
1.guest(游客)
<shiro:guest>
您当前是游客,<a href="javascript:void(0);" class="dropdown-toggle qqlogin" >登录</a>
</shiro:guest>
2.user(已经登录,或者记住我登录)
<shiro:user>
欢迎[<shiro:principal/>]登录,<a href="/logout.shtml">退出</a>
</shiro:user>
3.authenticated(已经认证,排除记住我登录的)
<shiro:authenticated>
用户[<shiro:principal/>]已身份验证通过
</shiro:authenticated>
4.notAuthenticated(和authenticated相反)
<shiro:notAuthenticated>
当前身份未认证(包括记住我登录的)
</shiro:notAuthenticated>
这个功能主要用途,识别是不是本次操作登录过的,比如支付系统,进入系统可以用记住我的登录信息,但是当要关键操作的时候,需要进行认证识别。
5.principal标签,这个要稍微重点讲讲。好多博客都是一下带过。
principal
标签,取值取的是你登录的时候。在Realm
实现类中的如下代码:
....
return new SimpleAuthenticationInfo(user,user.getPswd(), getName());
在new SimpleAuthenticationInfo(第一个参数,....)
的第一个参数放的如果是一个username
,那么就可以直接用。
<!--取到username-->
<shiro: principal/>
如果第一个参数放的是对象,比如我喜欢放User
对象。那么如果要取username
字段。
<!--需要指定property-->
<shiro:principal property="username"/>
和下面 Java 代码一致
User user = (User)SecurityUtils.getSubject().getPrincipals();
String username = user.getUsername();
6.hasRole标签(判断是否拥有这个角色)
<shiro:hasRole name="admin">
用户[<shiro:principal/>]拥有角色admin<br/>
</shiro:hasRole>
7.hasAnyRoles标签(判断是否拥有这些角色的其中一个)
<shiro:hasAnyRoles name="admin,user,member">
用户[<shiro:principal/>]拥有角色admin或user或member<br/>
</shiro:hasAnyRoles>
8.lacksRole标签(判断是否不拥有这个角色)
<shiro:lacksRole name="admin">
用户[<shiro:principal/>]不拥有admin角色
</shiro:lacksRole>
9.hasPermission标签(判断是否有拥有这个权限)
<shiro:hasPermission name="user:add">
用户[<shiro:principal/>]拥有user:add权限
</shiro:hasPermission>
10.lacksPermission标签(判断是否没有这个权限)
<shiro:lacksPermission name="user:add">
用户[<shiro:principal/>]不拥有user:add权限
</shiro:lacksPermission>