Shiro认证功能使用入门和简析

shiro做了个认证控制的demo。整个demo是基于session记录用户登录状态的。在本文中,将介绍shiro的最简使用方法和其执行流程的简析。

 

一、使用入门

1、在pom文件添加shiro的依赖

<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-all</artifactId>
   <version>1.2.2</version>
</dependency>

2、在web.xml中配置如下过滤器

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

3、在spring配置文件shiro.xml中配置如下bean

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <property name="securityManager" ref="securityManager"/>
    <!-- 登录url -->
    <property name="loginUrl" value="/login"/>
    <!-- 登录成功跳转的url -->
    <property name="successUrl" value="/home.jsp" />  
    <!-- url采用的过滤方式,anon表示不需要登录就可以访问的url,authc表示需要登录才可以访问 -->
    <property name="filterChainDefinitions">
        <value>
           /login.jsp                  = anon
           /**                         = authc
        </value>
    </property>
</bean>

需要注意的是这里的bean id一定要和web.xml中的filter-name一致。

4、写一个MyAuthorizingRealm继承AuthorizingRealm,重写如下两个方法

public class MyAuthorizingRealm extends AuthorizingRealm {
    //权限分配
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        return null;
    }
    
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                 throws AuthenticationException {
        return null;
    }
}

第一个方法是将用户拥有的权限封装到AuthorizationInfo对象返回,第二个方法用于用户身份认证,这个方法的操作一般是:

1)根据用户名从数据库查找用户对象;

2)如果找不到用户对象表示用户不存在,直接抛出异常,表示认证失败;

3)如果找到用户,将用户名和数据库查出来的密码封装到一个对象返回。

例如:

public class MyAuthorizingRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;
    @Autowired
    private RoleService roleService;
    @Autowired
    private PermissionService permissionService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals){
        String username = (String) principals.getPrimaryPrincipal();

        //获取用户的角色
        Set<String> roles = roleService.getRolesByUsername(username); 

        //获取用户的权限
        Set<String> permissions = permissionService.getPermsByUsername(username);
        
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        authorizationInfo.setRoles(roles);
        authorizationInfo.setStringPermissions(permissions);

        return authorizationInfo;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) 
                                 throws AuthenticationException {
        Object username = token.getPrincipal();    //获取用户名字
        Object password = token.getCredentials();  //获取密码

        if (ObjectUtils.isEmpty(username) || ObjectUtils.isEmpty(password)) {
            throw new UnknownAccountException("密码不能为空");
        }

        //通过用户名从数据库查询出对应的用户对象
        User user = userService.getUserByUsername((String) username);   

        //如果为空,则表示用户不存在,抛出异常,表示认证失败
        if (null == user) {
            throw new UnknownAccountException("用户不存在");
        }
         
        //如果不为空,将数据库的该用户账号密码取出封装到SimpleAuthenticationInfo对象中,
        //作为标准送入接下来的步骤中和用户输入的账号密码比对,
        //其中,ByteSource.Util.bytes(username)表示MD5加密的盐
        return new SimpleAuthenticationInfo(username, user.getPassword(), 
                   ByteSource.Util.bytes(username), getName());
    }

}

然后将这个realm配置到shiro.xml中

<bean id="myAuthorizingRealm" class="com.mytest.shiro.MyAuthorizingRealm">
    <!--密码加密验证方式-->
    <property name="credentialsMatcher">
        <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            <property name="hashAlgorithmName" value="MD5" />
            <property name="hashIterations" value="3" />
        </bean>
    </property>
</bean>

因为数据库一般不会储存明文密码,所以需要对用户输入的密码用和数据库密码一样的加密方式处理之后才可以和从simpleAuthenticationInfo对象里面的真实数据比对。所以在这里配置了密码加密方式。

5、最后在shiro.xml配置SecurityManager

<!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myAuthorizingRealm"/>
</bean>

SecurityManager是shiro的安全中心,将自定义的realm注入到安全中心。除了realm,还可以自定义其他很多组件。

写到这里,shiro部分的代码就写完了,把完整的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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login"/>
        <property name="successUrl" value="/home.jsp" />
        <property name="filterChainDefinitions">
            <value>
                /login.jsp                  = anon
                /**                         = authc
            </value>
        </property>
    </bean>

    <!-- Shiro默认会使用Servlet容器的Session,可通过sessionMode属性来指定使用Shiro原生Session -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="realm" ref="warehouseAuthorizingRealm"/>
    </bean>

    <bean id="warehouseAuthorizingRealm" class="com.mytest.shiro.myAuthorizingRealm">
        <!--密码加密验证方式-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5" />
                <property name="hashIterations" value="3" />
            </bean>
        </property>
    </bean>
</beans>

6、页面准备

登录页面:login.jsp

<%@ page pageEncoding="UTF-8" isELIgnored="false"%>
<html>
<head>
    <title>登录页面</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <h1>登录</h1>
    <form action="login" method="post">
        <p>用户名 : <input type="text" name="username"></p>
        <p>密码 : <input type="password" name="password"></p>
        <p><input type="submit" value="submit"></p>
    </form>
</body>
</html>

home页面:home.jsp

<%@ page pageEncoding="UTF-8" isELIgnored="false"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>

<html>
<head>
    <title>home页面</title>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
    <div>
        <h1>home</h1>
        <p>欢迎登录</p>
        <p><a href="<c:url value='/logout'/>">退出登录</a></p>
    </div>
    <div>
        <!-- 这是shiro的jsp标签,需要name熟悉里的权限才可以显示标签里面的内容 -->
        <shiro:hasPermission name="user:create">
            <p><a href="<c:url value='/admin/emplist.jsp'/>">员工管理权限</a></p>
        </shiro:hasPermission>
    </div>
</body>
</html>

7、测试

1)数据库植入一条用户数据

用户名:0001,密码:123(手动加密后为fe3accef6265a64b7f2805fddff85255);

2)启动tomcat服务器,进入登录页面;

3)输入错误的密码,用户名:0001,密码:1,登录失败;

4)输入正确的密码,登录成功。

 

二、流程简析

未完待续

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章