相信有很多的程序员,不愿意进行用户管理这块代码实现。

原因之一,不同的JavaEE 系统,用户管理都会有个性化的实现,逻辑很繁琐。

而且是系统门面,以后背锅的几率非常大,可谓是低收益高风险。

最近在系统中集成了 Shiro,感觉这个小家伙还是相当灵活的。

完善的用户认证和授权,干净的API,让人如沐春分。

Apache Shiro 作为一个强大而灵活的开源安全框架,它干净利落地处理身份认证,授权,企业会话管理和加密。

安全有时候是很复杂的,甚至是痛苦的,但它没有必要这样。框架应该尽可能掩盖复杂的地方,露出一个干净而直观的 API。

Apache Shiro 的首要目标是易于使用和理解。

以下是你可以用 Apache Shiro 所做的事情:

a.验证用户来核实他们的身份

b.对用户执行访问控制,如:

c.判断用户是否被分配了一个确定的安全角色。

d.判断用户是否被允许做某事。

e.在任何环境下使用 Session API,即使没有 Web 或 EJB 容器。

f.在身份验证,访问控制期间或在会话的生命周期,对事件作出反应。

g.聚集一个或多个用户安全数据的数据源,并作为一个单一的复合用户“视图”。

h.启用单点登录(SSO)功能。

i.并发登录管理(一个账号多人登录作踢人操作)。

j.为没有关联到登录的用户启用"Remember Me"服务。

以及更多——全部集成到紧密结合的易于使用的 API 中。

目前主流安全框架有 SpringSecurity 和 Shiro,相比于 SpringSecurity,Shiro 轻量化,简单容易上手。

SpringSecurity 太笨重了,难以上手,且只能在 Spring 里用,所以极力推荐Shiro。

本文重点描述集成过程,能让你迅速的将 Shiro 集成到 JavaEE 项目中,毕竟项目都挺紧张的。

1.前戏

Shiro 核心jar:

       <!--权限控制 shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>${shiro.version}</version>
</dependency> <dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-ehcache</artifactId>
<version>${shiro.version}</version>
</dependency>

JavaEE 应用开始的地方,web.xml 配置:

         <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>

Spring-Shiro-context 配置应用启动的使用,会帮助你做很多事情:

   <!--Shiro 关键过滤器配置-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager"/>
<property name="loginUrl" value="/sys/login"/> <!--请求 Url 为 get方式-->
<property name="successUrl" value="/sys/index"/>
<property name="filters">
<map>
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
<property name="filterChainDefinitions" ref="shiroFilterChainDefinitions"/>
</bean> <!-- Shiro 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="systemAuthorizingRealm"/>
<property name="cacheManager" ref="shiroCacheManager"/>
</bean> <!--自定义系统认证域-->
<bean id="systemAuthorizingRealm" class="com.rambo.spm.core.shiro.SysAuthorizingRealm"/> <!--shiro ehcache缓存-->
<bean id="shiroCacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManager" ref="cacheManagerFactory"/>
</bean> <!--扩展表单认证过滤器-->
<bean id="formAuthenticationFilter" class="com.rambo.spm.core.shiro.FormAuthenticationFilter"/> <!--权限过滤链定义 -->
<bean name="shiroFilterChainDefinitions" class="java.lang.String">
<constructor-arg>
<value>
/static/** = anon
/captcha-image = anon
/sys/login = authc
/sys/logout = logout
/** =user
</value>
</constructor-arg>
</bean> <!--借助 SpringAOP 扫描那些使用 Shiro 注解的类-->
<aop:config proxy-target-class="true"/> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager"/>
</bean> <!--用于在实现了Initializable/Destroyable接口的 Shiro bean 初始化时回调-->
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

2.个性化

请求发起的地方一般是前端,不管你是 .jsp/.php/.net.......方式都是类似

<html>
<body>
<h1>login page</h1>
<form id="" action="service/dologin" method="post">
<label>账号:</label><input name="userName" maxLength="40"/>
<input title="是否是管理员" type="checkbox" name="isAdmin"><label>是否为管理员</label><br>
<label>密码:</label><input title="密码" type="password" name="password" /><br>
<input type="submit" value="登录"/>
</form>
<%--用于输入后台返回的验证错误信息 --%>
<P><c:out value="${message }"/></P>
</body>
</html>

自定义项目验证域(验证域可以有多个,已可以有多种方式)。

public class SysAuthorizingRealm extends AuthorizingRealm {
private Log log = LogFactory.get(); @Autowired
private SysUserService sysUserService; @Autowired
private SysRoleService sysRoleService; @Autowired
private SysMenuService sysMenuService; /**
* 获取当前用户的认证信息
*
* @param authcToken 携带用户认证所需的信息
* @return 认证结果信息
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authcToken) throws AuthenticationException {
CaptchaUsernamePasswordToken spmToken = (CaptchaUsernamePasswordToken) authcToken;
log.info("token:{}", ReflectionToStringBuilder.toString(spmToken)); SysUser sysUser = sysUserService.getSysUserByLoginName(spmToken.getUsername());
if (sysUser == null) {
return null;
}
byte[] salt = Hex.decode(sysUser.getPasswd().substring(0, 16));
return new SimpleAuthenticationInfo(new SpmPrincipal(sysUser), sysUser.getPasswd().substring(16), ByteSource.Util.bytes(salt), getName());
} /**
* 获取当前用户授权信息
*
* @param principals 该用户身份集合
* @return 当前用户授权信息
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SpmPrincipal spmPrincipal = (SpmPrincipal) super.getAvailablePrincipal(principals);
log.info("授权当前:{}", ReflectionToStringBuilder.toString(spmPrincipal)); SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(); List<SysRole> sysRoleList = sysUserService.listSysRoleByUserId(spmPrincipal.getId());
for (SysRole sysRole : sysRoleList) {
info.addRole(sysRole.getRoleType()); List<SysMenu> sysMenuList = sysRoleService.listSysMenuByRoleId(sysRole.getUuid());
for (SysMenu sysMenu : sysMenuList) {
info.addStringPermission(sysMenu.getPermisson());
}
}
info.addStringPermission("user");
return info;
} /**
* 设定密码校验的Hash算法与迭代次数
*/
@PostConstruct
public void initCredentialsMatcher() {
HashedCredentialsMatcher matcher = new HashedCredentialsMatcher("SHA-1");
matcher.setHashIterations(1024);
setCredentialsMatcher(matcher);
}
}

请求的后台服务,在这里你可以在进行一点业务逻辑

   /**
* shiro 登录请求控制,真正的请求由 shiroFilter --> formAuthenticationFilter 进行处理
* 登录成功: 跳转配置的 succssUrl,不触发该方法;
* 登录失败: 触发该方法,可以从扩展的 formAuthenticationFilter 中获取具体的错误信息;
*/
@PostMapping("/sys/login")
public Object postSysLogin(HttpServletRequest httpRequest, ModelAndView modelAndView) {
String exceptionName = (String) httpRequest.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME); String errorMsg = null;
if (IncorrectCaptchaException.class.getName().equals(exceptionName)) {
errorMsg = "验证码错误!";
} else if (UnknownAccountException.class.getName().equals(exceptionName)) {
errorMsg = "用户不存在!";
} else if (IncorrectCredentialsException.class.getName().equals(exceptionName)) {
errorMsg = "用户或密码错误!";
} else if (exceptionName != null && StrUtil.startWith(exceptionName, "msg:")) {
errorMsg = StrUtil.removeAll(exceptionName, "msg:");
}
return setModelAndView(modelAndView, "sys/sysLogin", errorMsg);
}

整个集成工作就结束了,是不是简单的不要不要的。

等下次项目经理指派你做用户管理的时候,只需要花半天的时间做设计。

借助Shiro 半天时间实现代码。

然后将剩下的时间,做做自己喜欢的其他研究工作。

Spring MVC 急速集成 Shiro 实录的更多相关文章

  1. 细说shiro之五:在spring框架中集成shiro

    官网:https://shiro.apache.org/ 1. 下载在Maven项目中的依赖配置如下: <!-- shiro配置 --> <dependency> <gr ...

  2. mybatis实战教程(mybatis in action)之六:与Spring MVC 的集成

    前面几篇文章已经讲到了mybatis与spring 的集成.但这个时候,所有的工程还不是web工程,虽然我一直是创建的web 工程.今天将直接用mybatis与Spring mvc 的方式集成起来,源 ...

  3. spring mvc mybatis集成踩的坑

    开园这么多年了也没写几篇文章,现在想想光看别人的也不行啊,咱也自己写写,就写这天我我在做spring mvc与mybatis的集成时遇到的问题 1 spring与mybatis的集成 这个相信大家都弄 ...

  4. mybatis :与Spring MVC 的集成

    用mybatis与Spring mvc 的方式集成起来,源码在本文结尾处下载.主要有以下几个方面的配置1. web.xml 配置 spring dispatchservlet ,比如为:mvc-dis ...

  5. Mybatis学习(6)与Spring MVC 的集成

    前面几篇文章已经讲到了mybatis与spring 的集成.但这个时候,所有的工程还不是web工程,虽然我一直是创建的web 工程.今天将直接用mybatis与Spring mvc 的方式集成起来,源 ...

  6. Java Spring MVC项目搭建(一)——Spring MVC框架集成

    1.Java JDK及Tomcat安装 我这里安装的是JDK 1.8 及 Tomcat 8,安装步骤详见:http://www.cnblogs.com/eczhou/p/6285248.html 2. ...

  7. Spring MVC 中急速集成 Shiro 实践

    相信有很多的程序员,不愿意进行用户管理这块代码实现. 原因之一,不同的JavaEE 系统,用户管理都会有个性化的实现,逻辑很繁琐. 而且是系统门面,以后背锅的几率非常大,可谓是低收益高风险. 最近在系 ...

  8. Spring mvc 中有关 Shiro 1.2.3 配置问题

    Spring 版本:3.2.x,  4.0.x [问题说明] 首先介绍下配置出错情况: (1)项目中,Spring3 and Spring4 的 applicationContext.xml aop ...

  9. springboot (spring mvc)集成swagger

    最近用springboot构建rest接口,考虑到最方便的验证接口,想到了引入swagger. 基本的步骤大致如下: 1.pom中引入swagger依赖: <dependency> < ...

随机推荐

  1. ofbiz 本地化及邮件设置126邮箱

    ofibz登陆功能有通过电子邮件找会密码的功能,但找回密码功能需要配置一个发送email的邮箱账号和smtp服务器的配置,具体配置如下: 1:在ofbiz数据库的表product_store_emai ...

  2. ADO.Net(一)——增、删、改、查

    数据访问 对应命名空间:System.Data.SqlClient; SqlConnection:连接对象 SqlCommand:命令对象 SqlDataReader:读取器对象 CommandTex ...

  3. 说完Pivot 今天说下Unpivot 的处理方式

    上次说到,既然有Pivot 的行转列,那么肯定也有Unpivot 的列转行 .其实unpivot 处理的情况也是差不多,也是分3步走. 首先也是先演示一下unpivot 的用法 ),Mon TIME, ...

  4. 天朝使用GAE入门指南

    0. 引言 Across the Great Wall, we can reach every corner in the world. 洒家最近玩了几下 Google App Engine.由于众所 ...

  5. netfilter-在内核态操作网络数据包

    一.概述                                                    netfilter是自2.4内核的一个数据包过滤框架.可以过滤数据包,网络地址和端口转换 ...

  6. 150922-写写博客监督下不自觉的自己-PPT,Linux,HTML

    开始学PHP的日子里,总是懒散的有一天没一天的.无意间听闻写博客来展示代码(现在还远远做不到哇),来监督个人每天的学习进度,鉴于自己还是爱写一点文字,但愿可以坚持下去. 凡是都喜欢有个计划,骨子里的理 ...

  7. 阿里云+wordpress搭建个人博客网站【小白专用的图文教程】

    [声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/4 ...

  8. NOIP2006金明的预算方案[DP 有依赖的背包问题]

    题目描述 金明今天很开心,家里购置的新房就要领钥匙了,新房里有一间金明自己专用的很宽敞的房间.更让他高兴的是,妈妈昨天对他说:“你的房间需要购买哪些物品,怎么布置,你说了算,只要不超过N元钱就行”.今 ...

  9. C# Interlocked 笔记

    无锁代码下,在读写字段时使用内存屏障往往是不够的.在 64 位字段上进行加.减操作需要使用Interlocked工具类这样更加重型的方式.Interlocked也提供了Exchange和Compare ...

  10. linux内核启动以及文件系统的加载过程

    Linux 内核启动及文件系统加载过程 当u-boot 开始执行 bootcmd 命令,就进入 Linux 内核启动阶段.普通 Linux 内核的启动过程也可以分为两个阶段.本文以项目中使用的 lin ...