shiro与项目集成开发
shiro与spring web项目开发
加入shiro的jar包
自定义realm
/**
* 自定义realm 继承授权realm
* @author Administrator
*
*/
public class CustomRealm extends AuthorizingRealm{ @Autowired
UserMapper userMapper;
@Autowired
MenuMapper menuMapper; @Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
UsernamePasswordToken upToken = (UsernamePasswordToken) token;
String username = upToken.getUsername(); // Null username is invalid
if (username == null) {
throw new AccountException("账号不能为空");
} //模拟数据库获取数据
User user = userMapper.findUserByUsername(username);
//通过数据库获取username的信息
if (user==null) {
return null;
}
SessionUser sessionUser = new SessionUser();
sessionUser.setUser(user);
//查询用户对应的菜单资源
List<Menu> menu = menuMapper.getMenu(user.getId(), "menu");
sessionUser.setMenus(menu);
//查询用户对应的按钮资源
List<Menu> button = menuMapper.getMenu(user.getId(), "button");
sessionUser.setButtons(button);
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(sessionUser, user.getPassword(),ByteSource.Util.bytes("tdit"), getName()); return info;
} /**
* 实现授权的方法 principals ======认证保存的SimpleAuthenticationInfo对象
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
if (principals == null) {
throw new AuthorizationException("PrincipalCollection method argument cannot be null.");
} SessionUser sessionUser= (SessionUser) getAvailablePrincipal(principals);
List<String>permissions = new ArrayList<>();
//模拟通过用户名查询数据库权限信息
List<Menu> buttons = sessionUser.getButtons();
for (Menu menu : buttons) {
permissions.add(menu.getMenuCode());
} SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
info.addStringPermissions(permissions);
return info;
} }
添加spring-shiro.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 http://www.springframework.org/schema/context/spring-context.xsd"> <bean id="shiroSecurityFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 配置安全管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 登录的url 指的是提交登录信息的url login.do -->
<property name="loginUrl" value="/login.do"/>
<!-- 认证通过跳转的页码 只在浏览器第一次请求系统的时候起作用,之后就不起作用了 一般不需要配,默认跳转到你前一次请求的路径 -->
<!-- <property name="successUrl" value="/main.do"></property> -->
<!-- 授权没有通过跳转的页面 可以指定错误页面-->
<property name="unauthorizedUrl" value="error.jsp"/>
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"></entry>
</map>
</property> <!-- shiro 连接约束配置 -->
<property name="filterChainDefinitions">
<value>
/index.do=anon<!--登录页面可以匿名访问 -->
/logout.do=logout<!-- 退出过滤器 -->
/**=authc<!-- 需要认证才可访问 -->
</value>
</property>
</bean>
<!-- 配置登录form 登录用户名name属性,密码name属性 存放错误信息的key值 -->
<bean id="formAuthenticationFilter" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">
<property name="usernameParam" value="user"/>
<property name="passwordParam" value="pwd"/>
<!-- request 域中错误信息的key 用户login.do中获取认证错误信息 -->
<property name="failureKeyAttribute" value="shiroException"/>
</bean> <!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="customRealm"/>
</bean> <!-- 配置自定义realm -->
<bean id="customRealm" class="com.td.realm.CustomRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean> <!-- 配置认证器 -->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="2"/>
</bean>
</beans>
securityManager:这个属性是必须的。
loginUrl:没有登录认证的用户请求将跳转到此地址,不是必须的属性,不输入地址的话会自动寻找项目web项目的根目录下的”/login.jsp”页面。
unauthorizedUrl:没有权限默认跳转的页面。
shiro过滤器
anon:例子/admins/**=anon 没有参数,表示可以匿名使用。
authc:例如/admins/user/**=authc表示需要认证(登录)才能使用,没有参数
roles:例子/admins/user/**=roles[admin],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,当有多个参数时,例如admins/user/**=roles["admin,guest"],每个参数通过才算通过,相当于hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],参数可以写多个,多个时必须加上引号,并且参数之间用逗号分割,例如/admins/user/**=perms["user:add:*,user:modify:*"],当有多个参数时必须每个参数都通过才通过,想当于isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根据请求的方法,相当于/admins/user/**=perms[user:method] ,其中method为post,get,delete等。
port:例子/admins/user/**=port[8081],当请求的url的端口不是8081是跳转到schemal://serverName:8081?queryString,其中schmal是协议http或https等,serverName是你访问的host,8081是url配置里port的端口,queryString
是你访问的url里的?后面的参数。
authcBasic:例如/admins/user/**=authcBasic没有参数表示httpBasic认证
ssl:例子/admins/user/**=ssl没有参数,表示安全的url请求,协议为https
user:例如/admins/user/**=user没有参数表示必须存在用户,当登入操作时不做检查
注:
这些过滤器分为两组,一组是认证过滤器,一组是授权过滤器。
anon,authcBasic,auchc,user是认证过滤器,
perms,roles,ssl,rest,port是授权过滤器
FormAuthenticationFilter 拦截器
通过查看默认的拦截器链 最终发现进行认证拦截的是FormAuthenticationFilter这个拦截器
进入它的父类AuthenticationFilter 可以看到执行的login的方法这里边发现如果登录失败,会回调FormAuthenticationFilter的一个登录失败的方法
最终取到的就是上边默认的错误属性名 shiroLoginFailure
自定义拦截器
web.xml添加shiro Filter
<!-- 配置shiro拦截器 -->
<filter>
<filter-name>shiroFilter</filter-name>
<!-- 配置一个代理拦截器 因为项目启动之后 shiro的拦截器还没有加载,需要通过代理拦截器 来进行分配 -->
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<!-- 设置true由servlet容器控制filter的生命周期 false 由pring来控制生命周期-->
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!-- 指定拦截器的名称,如果不配置默认查找和拦截器名称(filter-name)相同的拦截器对象 -->
<init-param>
<param-name>targetBeanName</param-name>
<!-- 配置的拦截器名称需要和spring-shiro.xml中的bean id 一样 -->
<param-value>shiroFilter</param-value>
</init-param>
</filter> <filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.do</url-pattern>
</filter-mapping>
登录controller
/**
* 提交登录的方法
* @param request
* @param model
* @return
*/
@RequestMapping("/login")
public ModelAndView login(HttpServletRequest request,Model model) {
// 认证失败 过滤器会把异常信息放入request域中 key 为shiroLoginFailure
//所以在这里可以通过request获取到错误信息
String shiroLoginFailure = (String) request.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
if (shiroLoginFailure!=null) {
if(UnknownAccountException.class.getName().equals(shiroLoginFailure)) {
model.addAttribute("error", "账号错误");
}else if(IncorrectCredentialsException.class.getName().equals(shiroLoginFailure)) {
model.addAttribute("error", "密码错误");
}else {
model.addAttribute("error", "认证错误");
}
}
return new ModelAndView("forward:index.do");
} /**
* 登录页面
* @return
*/
@RequestMapping("/index")
public String index() {
return "login";
}
登录页面
<form class="loginForm" action="${ctx}/login.do" method="post">
<div class="inputbox">
<label for="user">用户名:</label>
<input id="username" type="text" name="usercode" placeholder="请输入用户名" onchange="checkUser()" required/>
<span id="usernameError" style="color:red;"></span>${userError}
</div>
<div class="inputbox">
<label for="password">密码:</label>
<input id="password" type="password" name="pwd" placeholder="请输入密码" required/>
<span style="color:red;">${pwdError}</span>
</div>
<div class="subBtn">
<input type="submit" value="登录" />
<input type="reset" value="重置"/>
</div> </form>
退出
由于使用shiro的sessionManager,不用开发退出功能,使用shiro的logout拦截器即可。
<!-- 退出拦截,请求logout.action执行退出操作 -->
/logout.do = logout
自定义FormAuthenticationFilter实现登录跳转到main.do页面
经过测试发现successUrl只在浏览器第一次请求的时候才会跳转,之后再次登录不会跳转 ,查看源码发现shiro先查询session中是否有记录(上次请求),如果有获取到上次请求的记录中的url 然后跳转过去,如果没有session才会跳转到successUrl的连接中 ,所有我们只需要在跳转之前情况session即可。
以下为自定义过滤器实现情况的操作
public class MyFormAuthenticationFilter extends FormAuthenticationFilter{ @Override
protected boolean onLoginSuccess(AuthenticationToken token, Subject subject, ServletRequest request,
ServletResponse response) throws Exception {
WebUtils.getAndClearSavedRequest(request);//情况session
// WebUtils.redirectToSavedRequest(request,response,"/main.do");
return super.onLoginSuccess(token, subject, request, response);
}
}
现在就可以放开successUrl的连接了
配置自定义拦截器
使用shiro注解授权
在springmvc.xml中配置shiro注解支持,可在controller方法中使用shiro注解配置权限:
<!-- 开启aop,对类代理 -->
<aop:config proxy-target-class="true"></aop:config>
<!-- 开启shiro注解支持 -->
<bean
class="
org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
修改Controller代码,在方法上添加授权注解,如下:
/**
* 进入添加用户页面
* @return
*/
@RequiresPermissions("user:add")
@RequestMapping("/userAddPage")
public String userAddPage() {
return "userAdd";
}
上边代码@RequiresPermissions("user:add")表示必须拥有“user:add”权限方可执行。
无权限refuse.jsp
权限拦截会抛出UnauthorizedException
在spring-mvc.xml中配置
<!-- 接收注解方式抛出的异常 unauthorizedException -->
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<!-- refuse 跳转到错误页面名称 -->
<prop key="org.apache.shiro.authz.UnauthorizedException">refuse</prop>
</props>
</property>
</bean>
shiro的jsp标签
Jsp页面添加:
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>
session管理
在spring-shiro.xml中配置SessionManager
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<property name="sessionManager" ref="sessionManager" />
</bean>
<!-- 会话管理器 -->
<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
<!-- session的失效时长,单位毫秒 -->
<property name="globalSessionTimeout" value="600000"/>
<!-- 删除失效的session -->
<property name="deleteInvalidSessions" value="true"/>
</bean>
缓存
shiro每个授权都会通过realm获取权限信息,为了提高访问速度需要添加缓存,第一次从realm中读取权限数据,之后不再读取,这里Shiro和Ehcache整合。
添加Ehcache的jar包
配置
在applicationContext-shiro.xml中配置缓存管理器。
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="cacheManager"/>
</bean> <!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
</bean>
验证码
自定义FormAuthenticationFilter
需要在验证账号和名称之前校验验证码。
public class MyFormAuthenticationFilter extends FormAuthenticationFilter {
protected boolean onAccessDenied(ServletRequest request,
ServletResponse response, Object mappedValue) throws Exception { // 校验验证码
// 从session获取正确的验证码
HttpSession session = ((HttpServletRequest)request).getSession();
//页面输入的验证码
String randomcode = request.getParameter("randomcode");
//从session中取出验证码
String validateCode = (String) session.getAttribute("validateCode");
if (!randomcode.equals(validateCode)) {
// randomCodeError表示验证码错误
request.setAttribute("shiroLoginFailure", "randomCodeError");
//拒绝访问,不再校验账号和密码
return true;
} return super.onAccessDenied(request, response, mappedValue);
}
}
修改FormAuthenticationFilter配置
修改applicationContext-shiro.xml中对FormAuthenticationFilter的配置。
<bean id="formAuthenticationFilter"
class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter"> 改为 <bean id="formAuthenticationFilter"
class="cn.td.tderp.shiro.MyFormAuthenticationFilter">
登录页面
添加验证码
<TR>
TD>验证码:</TD>
<TD>
<input id="randomcode" name="randomcode" size="8" />
<img id="randomcode_img" src="${baseurl}validatecode.jsp" alt=""
width="56" height="20" align='absMiddle' />
<a href=javascript:randomcode_refresh()>刷新</a>
</TD>
</TR>
配置validatecode.jsp匿名访问
修改spring-shiro.xml:
记住我
用户登陆选择“自动登陆”本次登陆成功会向cookie写身份信息,下次登陆从cookie中取出身份信息实现自动登陆。
配置
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="userRealm" />
<property name="sessionManager" ref="sessionManager" />
<property name="cacheManager" ref="cacheManager"/>
<!-- 记住我 -->
<property name="rememberMeManager" ref="rememberMeManager"/>
</bean> <!-- rememberMeManager管理器 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie" />
</bean>
<!-- 记住我cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<constructor-arg value="rememberMe" />
<!-- 记住我cookie生效时间30天 -->
<property name="maxAge" value="2592000" />
</bean>
修改formAuthenticationFitler添加页面中“记住我checkbox”的input名称:
<bean id="formAuthenticationFilter"
class="com.td.bill.shiro.MyFormAuthenticationFilter">
<!-- 表单中账号的input名称 -->
<property name="usernameParam" value="usercode" />
<!-- 表单中密码的input名称 -->
<property name="passwordParam" value="password" />
<property name="rememberMeParam" value="rememberMe"/>
<!-- loginurl:用户登陆地址,此地址是可以http访问的url地址 -->
<property name="loginUrl" value="/login.do" />
</bean>
登陆页面
在login.jsp中添加“记住我”checkbox。
<TR>
<TD></TD>
<TD><input type="checkbox" name="rememberMe" />自动登陆</TD>
</TR>
shiro与项目集成开发的更多相关文章
- Eclipse 下Spring cloud项目集成开发插件Spring Tool Suite (STS) 安装
安装eclipse插件 Help->Eclipse Marketplace-> Search中查找"Spring Tool Suite (STS) for Eclipse&quo ...
- 【CC2530入门教程-01】IAR集成开发环境的建立与项目开发流程
[引言] 本系列教程就有关CC2530单片机应用入门基础的实训案例进行分析,主要包括以下6部分的内容:1.CC2530单片机开发入门.2.通用I/O端口的输入和输出.3.外部中断初步应用.4.定时/计 ...
- 07-java学习-方法重载-idea集成开发工具学习-项目-模块-包
方法重载的概念? 方法重载的好处? 集成开发工具idea的学习 下载 安装 设置 建项目 导入项目 建模块 导入模块 建包 复制粘贴包 建类 复制粘贴类 运行 调试
- iOS-Cordova集成开发,已有项目集成cordova
iOS-Cordova集成开发,已有项目集成cordova 项目组准备开发一个APP,要求Android和iOS端页面完全一致,除了一个页面跟业务相关的不同,其他界面基本一致,因此,萌生一个想法,关于 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:1、服务端:注册中心、网关(提供可运行程序下载)。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:2、客户端:ASP.NET Core(C#)项目集成:应用中心。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:5、统一的日志管理。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:4、默认安全认证与自定义安全认证。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 本系列第一篇:Taurus.MVC V3.0.3 微服务开源框架发布:让.NET 架构在大并发的演进过程更简单 ...
- Taurus.MVC 微服务框架 入门开发教程:项目集成:3、客户端:其它编程语言项目集成:Java集成应用中心。
系列目录: 本系列分为项目集成.项目部署.架构演进三个方向,后续会根据情况调整文章目录. 开源地址:https://github.com/cyq1162/Taurus.MVC 本系列第一篇:Tauru ...
随机推荐
- 【noip模拟赛4】Matrix67的派对 暴力dfs
[noip模拟赛4]Matrix67的派对 描述 Matrix67发现身高接近的人似乎更合得来.Matrix67举办的派对共有N(1<=N<=10)个人参加,Matrix67需要把他们 ...
- 转*SqlSever查询某个表的列名称、说明、备注、注释,类型等
@原文地址 关键部分如下: ------sqlserver 查询某个表的列名称.说明.备注.类型等 SELECT 表名 then d.name else '' end, 表说明 then isnull ...
- VS2015一新建项目就出现未将对象引用设置到对象的实例怎么办?[z]
https://blog.csdn.net/tiandyoin/article/details/79722800 在控制面板-卸载或修复程序太麻烦,而且不一定保证解决,可以这样------打开--C: ...
- 部署代码review和CI
公司原先搭了一个代码Review的服务器,由于历史原因,装的是一个32bit的Ubuntu系统,后来由于需要,需要安装gitlab,由于gitlab需要64位系统,所以临时凑合了个vagrant,本质 ...
- web 文件上传的几种方式
问题 文件上传在WEB开发中应用很广泛. 文件上传是指将本地图片.视频.音频等文件上传到服务器上,可以供其他用户浏览或下载的过程. 以下总结了常见的文件(图片)上传的方式和要点处理. 表单上传 这是传 ...
- Mysql运行状态查询命令及调优详解
(转载自点击打开链接) MySQL运行状态及调优(一) 一.查看MySQL运行情况SHOW STATUS; 二.查看INNODB数据库引擎运行状态SHOW ENGINE INNODB STATUS; ...
- python课程安排
作为最流行的脚本语言之一,python具有内置的高级数据结构和简单面向对象编程思想实现.同时,其语法简洁而清晰,类库丰富而强大,非常适合进行快速原型开发.另外,python可以运行在多种系统平台下,从 ...
- SQL Server数据库的兼容级别
SQL Server 是Microsoft 公司推出的关系型数据库管理系统.具有使用方便可伸缩性好与相关软件集成程度高等优点,可跨越从运行Microsoft Windows 98 的膝上型电脑到运行M ...
- dotNet程序员的Java爬坑之旅(三)之spring MVC篇一
使用maven構建springMVC項目,開發工具為IDEA 一.構建Maven項目,模板為WebApp 二.在pom文件中配置SpringMvc配置(springMvc需要以來servlet ,如本 ...
- pytest 一.安装和使用入门
pytest --fixtures Python版本: Python 2.7.3.4.3.5.3.6.Jython.PyPy-2.3 平台:Unix / Posix和windows PyPI包名称:p ...