一、概念
shiro是一个安全框架,主要可以帮助我们解决程序开发中认证和授权的问题。基于拦截器做的权限系统,权限控制的粒度有限,为了方便各种各样的常用的权限管理需求的实现,我们有必要使用比较好的安全框架,于是就出现了shiro安全框架,学习成本降低了很多,而且基本的功能也比较完善。
二、shiro提供的功能
1、Authentication:身份认证/登陆,验证用户是不是拥有相对应的身份;
2、Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者粒度的验证某个用户对某个资源是否具有权限;
3、Session Manager:会话管理,即用户登陆后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是Web环境的;
4、Cryptographt:加密,保护数据,如密码加密存储到数据库,而不是明文存储;
5、Web Support:Web支持,可以非常容易的继承到Web环境的;
6、Caching:缓存,比如用户登陆后,其用户信息、拥有的角色/权限不必每次去查,这样提高效率;
7、Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
8、Testing:提供测试支持;
9、Run As:允许一个用户假装另一个用户(如果我们允许)的身份进行访问;
10、Remember Me:记住我,这个是非常常见的功能,即一次登陆后,下次再来的话不用登陆了。
三、Shiro实现原理理解
也就是说对于我们而言,最简单的一个 Shiro 应用,通过 Subject 来进行认证和授权,而 Subject 又委托给 SecurityManager; 我们需要给 Shiro 的 SecurityManager 注入 Realm,从而SecurityManager 能得到合法的用户及其权限进行判断。
四、shiro的认证示例(Maven工程)
1.在pom.xml引入需要的jar包,可以去maven仓库官网复制
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.hyt</groupId>
<artifactId>blog</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>war</packaging>
<dependencies>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId><version>1.0.4</version>
</dependency>
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-core</artifactId>
<version>1.3.0</version>
</dependency>
<!-- 导入shiro和spring继承的jar包 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.2.3</version>
</dependency>
<!-- 导入shiro和web的jar包-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-web</artifactId>
<version>1.2.3</version>
</dependency>
</dependencies>
</project>
2.在web.xml中声明shiro拦截权限的过滤器
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
<init-param>
<!--保证该过滤器的生命周期和spring 工厂中shiro过滤器对象的生命周期一致-->
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
<!--声明该过滤器代理工厂类中的id为什么的shiro过滤器对象-->
<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>
3.在spring的主配置文件汇总声明shiro的配置信息
<!--创建自定义域对象-->
<bean id="MyRealm" class="com.hyt.realm.MyRealm"></bean>
<!--创建shiro的安全管理器对象-->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--要声明域,在域中读取认证和授权的数据-->
<property name="realm" ref="MyRealm"></property>
</bean>
<!--创建shiro的过滤器对象-->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!--要注入安全管理器对象-->
<property name="securityManager" ref="securityManager"></property>
<!--配置登录请求的路径-->
<property name="loginUrl" value="/user/login.do"></property>
<!--配置shiro认证和授权的过滤器-->
<property name="filterChainDefinitions">
<value>
<!--对静态资源不拦截-->
<!--anon指匿名访问的过滤器,所有匿名用户都可以访问static下面的资源-->
/login.jsp=anon
<!--authc指必须经过认证(登录过之后)才能访问的请求 /*代表所有有一个斜杠的请求都要经过认证 -->
/admin/**=authc
</value>
</property></bean>
</beans>
4.创建自定义域对象MyRealm
package com.hyt.realm;
import javax.annotation.Resource;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import com.hyt.entity.Blogger;
import com.hyt.service.BloggerService;
import com.hyt.util.Const;
public class MyRealm extends AuthorizingRealm {
@Resource
private BloggerService bloggerService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
// TODO Auto-generated method stub
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String userName=(String)token.getPrincipal();
Blogger blogger=bloggerService.getByUserName(userName);
if(blogger!=null) {
SecurityUtils.getSubject().getSession().setAttribute(Const.CURRENT_USER, blogger);
AuthenticationInfo authenInfo=new SimpleAuthenticationInfo(blogger.getUserName(), blogger.getPassword(),getName());
return authenInfo;
}
return null;
}
}
5.在控制器(Controller)中使用shiro去做登陆认证
package com.hyt.controller;
import javax.servlet.http.HttpServletRequest;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.hyt.entity.Blogger;
import com.hyt.util.CryptographyUtil;
/**
* 博主登录相关
*
*/
@Controller
@RequestMapping("/blogger")
public class BloggerController {
@RequestMapping("/login")
public String login(Blogger blogger,HttpServletRequest request) {
String userName=blogger.getUserName();
String password=blogger.getPassword();
String pw=CryptographyUtil.md5(password,"amos");
Subject subject=SecurityUtils.getSubject();
UsernamePasswordToken token=new UsernamePasswordToken(userName,pw);
try {
//传递token给shiro的realm
subject.login(token);
return "redirect:/admin/main.jsp";
} catch (Exception e) {
e.printStackTrace();
request.setAttribute("blogger", blogger);
request.setAttribute("errorInfo", "用户名或密码错误!");
}
//return "redirect:../login.jsp";
return "login";
}
}
6.采用MD5加密,以下是MD5加密工具类(给md5加点“盐”,加密型更高)
package com.hyt.util;
import org.apache.shiro.crypto.hash.Md5Hash;
public class CryptographyUtil {
public static String md5(String str,String salt) {
return new Md5Hash(str,salt).toString();
}
public static void main(String[] args) {
System.out.println(md5("991109","amos"));
}
}
密码加密存储之后,使用shiro做校验时,应该在realm中做如下配置:
<!--创建自定义域对象-->
<bean id="MyRealm" class="com.hyt.realm.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher"></property>
</bean>
<!-- 创建凭证匹配器对象-->
<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--指定要对用户传过来的明文的密码最什么加密-->
<property name="hashAlgorithmName" value="md5"></property>
<!--指明hash迭代的次数-->
<property name="hashIterations" value="10"></property>
</bean>
以上代码内容提取于最近在写的SSM框架下的个人博客项目。