在Web项目中使用shiro

1.先导入所需要的依赖包

2.【shiro-web】依赖库引用完成之后,需要修改web.xml配置文件

  • 进行shiro整合一定要在web.xml配置文件中配置一个Shiro环境监听器

  • 在任何一个shiro项目里面都睡存在有一个shiro.ini配置文件,需要在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">
  <listener><!--shiro环境监听器-->
    <listener-class>
      org.apache.shiro.web.env.EnvironmentLoaderListener
    </listener-class>
  </listener>
  <filter><!--过滤shiro.ini配置文件-->
    <filter-name>ShiroFilter</filter-name>
    <filter-class>
      org.apache.shiro.web.servlet.ShiroFilter
    </filter-class>
    <init-param>
      <param-name>configPath</param-name>
      <param-value>classpath:shiro.ini</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>ShiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
  </filter-mapping>
</web-app>

3.src/main/resources/目录下的shiro.ini配置文件:ini文件中主要配置有四大类:main,users,roles,urls

  ● main:配置shiro对象,例如securityManager,Realm,authenticator,autchStrategy等等

  ● users:配置静态的用户信息,包含用户名,密码,角色,一个用户可以拥有多个角色。如:lee=hello,member,dept  其中lee为用户名,hello为密码,member和dept为角色

  ● roles:定义角色与权限的关联。如:member=member:add,member:list,member:edit  其中代表着member角色下的add,list和edit权限

  ● urls:配置主要在web应用中,格式为:url=拦截器[参数],拦截器[参数],...。如:/login.jsp=anon

4.自定义Realm:

  ● 自定义Realm一定要实现Realm接口并覆写其中的三个方法,例如以下代码

package com.yootk.shiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.realm.Realm;

public class MyselfDefaultRealm implements Realm {
    private static int count = 0 ;
    @Override
    public String getName() {   // 获取Realm的名称
        return "my-happy-realm - " + count++;
    }

    @Override
    public boolean supports(AuthenticationToken token) {    // 判断当前的Token是否可以使用此Realm
        return token instanceof UsernamePasswordToken; // 当前Realm只支持“UsernamePasswordToken”类型
    }

    @Override
    public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        String mid = (String) token.getPrincipal() ;    // 获取用户名
        String password = new String((char[]) token.getCredentials()) ; // 获取密码
        if (!"lee".equals(mid)) {   // 此时用户名不存在
            throw new UnknownAccountException("【"+mid+"】该用户信息不存在,请确认输入的用户名!") ;
        }
        if (!"hello".equals(mid)) { // 密码不正确
            throw new IncorrectCredentialsException("错误的用户名或密码!") ;
        }
        return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName()) ;
    }
}

  ● 编写完自定义Ream类之后需要在shiro.ini配置文件中配置一下

[main]
#要想让自定义的Realm生效一定要配置这两项 # 将自定义的Realm定义在配置文件之中,表示此类的对象将由Shiro类负责实例化 myselfRealm=com.yootk.shiro.realm.MyselfDefaultRealm # 此时的配置就表示调用了SecurityManager子类中的setRealms()方法进行设置,内部引用使用“$”符号 securityManager.realms=$myselfRealm [urls] #web项目一定要设置过滤链,否则会报缺少FilterChainResolver /login.jsp=anon

5.配置JDBC认证信息,系统里面不仅仅只包含有自定义Realm,同时还提供有一种JdbcRealm程序,这类程序的最大特点是可以直接进行数据库的认证信息。

  ● 想使用JdbcRealm,首先需要修改pom.xml配置文件引入mysql-connector-java依赖包

  ● 修改shiro.ini配置文件,引入JdbcRealm进行程序的处理

[main]
# 定义当前项目之中要使用的DataSource,此时的DataSource为MySQL驱动自带
dataSource=com.mysql.jdbc.jdbc2.optional.MysqlDataSource
#dataSource.url=jdbc:mysql://localhost:3306/yootk_authentication
dataSource.serverName=localhost
dataSource.port=3306
dataSource.databaseName=yootk_authentication
dataSource.user=root
dataSource.password=mysqladmin
# 定义JdbcRealm类型,为当前的使用Realm
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
# 为JdbcRealm设置要使用的数据源
jdbcRealm.dataSource=$dataSource
# 设置数据库的查询操作指令
jdbcRealm.authenticationQuery=SELECT password FROM member WHERE mid=? AND locked=0
# 将当前使用的Realm整合在SecurityManager之中
securityManager.realms=$jdbcRealm
[urls]
/login.jsp=anon

6.Realm与Subject与token与SececurityManager与SecurityUtils的关系

  ● 首先创建一个SececurityManager的实例

  ● Realm设置数据源,读取shiro.ini文件

  ● SececurityManager的实例设置上具体的Realm对象

  ● SecurityUtils设置上SececurityManager的实例

  ● 通过SecurityUtils.getSubect获得Subject的对象

  ● 实例化对象token并向token中存入用户名和密码

  ● 采用subject.login(token)认证

package com.yootk.test;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.junit.Test;

public class TestShiroBase {
    public static final String USERNAME = "lee" ;   // 假设此处内容为输入数据
    public static final String PASSWORD = "hello" ;  // 假设此处内容为输入数据
    @Test
    public void testAuth() throws Exception {

        // 1、创建一个SececurityManager接口类的对象实例,使用子类为了设置realm
        DefaultSecurityManager securityManager = new DefaultSecurityManager() ;
        // 2、所有的认证信息都保存在shiro.ini文件,这个文件存储在CLASSPATH目录下;
        Realm realm = new IniRealm("classpath:shiro.ini") ;
        // 3、此时的SecurityManager需要设置上具体的realm对象信息
        securityManager.setRealm(realm);
        // 4、如果要想进行数据的认证处理,还需要获取SecurityUtils工具类
        SecurityUtils.setSecurityManager(securityManager); // 设置安全管理类实例
        // 5、如果要继续用户认证处理,则首先一定要获取一个Subject(用户)
        Subject subject = SecurityUtils.getSubject();
        // 6、利用一个专属的认证Token的结构包装输入的用户名与密码信息
        AuthenticationToken token = new UsernamePasswordToken(USERNAME,PASSWORD) ;
        // 7、利用Subject实现最终的用户认证处理操作
        subject.login(token); // 进行认证操作
        System.out.println("用户名:" + subject.getPrincipal());
    }
}

7.以后开发的时候编写自定义Realm类的时候一般会继承AuthorizingRealm类,然后覆写其中的认证和授权方法。

  ● 认证方法是doGetAuthenticationInfo():参数类型.getPrincipal()是获取用户名,参数类型.getCredentials()是获取密码,返回值类型是new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());

  ● 授权方法是doGetAuthorizationInfo():SimpleAuthorizationInfo authz = new SimpleAuthorizationInfo() ; // 返回的授权信息  ;authz.setRoles(map.get("allRoles"));//设置角色;authz.setStringPermissions(map.get("allActions"));//设置权限;return authz;//返回对象

package com.yootk.shiro.realm;

import com.yootk.shiro.service.IMemberService;
import com.yootk.shiro.service.impl.MemberServiceImpl;
import com.yootk.shiro.vo.Member;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

// 实现用户认证与授权处理的操作
public class MemberRealm extends AuthorizingRealm {
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // 本处的程序要进行用户认证的处理操作
        System.out.println("【MemberRealm】============== 用户认证处理 ==============");
        String mid = (String) token.getPrincipal() ;
        IMemberService memberService = new MemberServiceImpl() ; // 获取业务层接口实例
        Member member = memberService.get(mid) ; // 根据mid查询用户信息
        if (member == null) {   // 用户信息不存在
            throw new UnknownAccountException(mid + "账户信息不存在!") ;
        }
        String password = new String((char[]) token.getCredentials()) ;
        if (!member.getPassword().equals(password)) {   // 密码不同
            throw new IncorrectCredentialsException("错误的用户名或密码!");
        }
        if (member.getLocked().equals(1)) { // 用户锁定了
            throw new LockedAccountException(mid + "账户已经被锁定!");
        }
        return new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());
    }
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("【MemberRealm】============== 用户授权处理 ==============");
        return null;
    }

}

8.Shiro页面标签,修改welcome.jsp,采用shiro.jsp标签来进行控制

  ● 采用标签输出用户名:

<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %><!--首先要导入此标签-->
<h1>用户登录成功,欢迎“<shiro:principal/>”光临"</h1>

  ● 在用户登录界面上,根据用户是否登录过来进行表单是否显示的判断,采用如下标签用来判断用户的登录状态:

<shiro:authenticated>
    <h3>您已经登录过了!</h3>
</shiro:authenticated>

 <shiro:notAuthenticated>
    <h3>您还未登录,显示登录表单!</h3>
   </shiro:notAuthenticated>

  ● 进行用户授权的检测处理:

<shiro:hasPermission name="member:add">
    <h3>当前用户拥有“member:add”的权限!</h3>
</shiro:hasPermission>

9.路径访问策略:

  ● 下面这些属性对应的都是后面配置文件中的拦截器

    ● anon 允许匿名访问,不登录也可以访问

    ● authc 认证用户可以访问

    ● logout 注销访问

    ● noSessionCreation 第一次允许访问(如果没有session可以访问,如果有session可以访问)

    ● perms 权限检测访问

    ● roles 角色检测访问

    ● ssl ssl访问,检测http协议

    ● user RememberMe用户访问

    例如下面的shiro.ini文件:

[main]
# 将自定义的Realm直接出现在当前的程序之中
memberRealm=com.yootk.shiro.realm.MemberRealm
# 将当前使用的Realm整合在SecurityManager之中
securityManager.realms=$memberRealm
# 当路径检测失败的时候,应该跳转到登录页面,此处设置登录页面路径
shiro.loginUrl=/login.jsp
[users]
admin=hello,member,dept
lee=hello,member
[roles]
member=member:add,member:list,member:edit
dept=dept:add,dept:list,dept:edit
[urls]
/login.jsp=anon
/pages/**=authc,roles[member],perms["member:add"]

  ● 如果要想使用这些进行访问处理,那么还需要进行一些良好的路径匹配,就可以使用以下通配符:

    ● "?":匹配任意的0个或1个的内容,例如:"/pages?"表示"/pages1","/pages2"匹配

    ● "*":匹配任意的0个,1个或多个内容,例如:"/pages*"表示"/pages","/pageslee"都可以匹配

    ● "**":匹配任意级的目录,例如:"/pages/**"表示匹配"/pages/"下的所有路径,如:/pages/**=authc

  ● 除了路径匹配之外,也可以进行角色或权限的匹配:

    如:/pages/**=authc,roles[member],perms["member:add"]

 

posted @ 2019-07-10 01:46  王兴龙123  阅读(734)  评论(0编辑  收藏  举报