Shiro安全框架

Shiro 的简介

A、 为什么学习 Shiro

目前使用遇到的问题?
[1]使用 RBAC 进行角色访问控制的时候,代码书写起来相对 比较麻烦

[2]目前学习的写的操作代码整体不太安全

B、解决的方案

[1]Spring securing 安全框架 缺点:基于 Spring 之上 的,局限性比较大

[2]shiro javaEE javaSE 分布式项目

C、 什么是 shiro

Apache Shiro 是一个强大而灵活的开源安全框架,它干净利 落地处理身份认证,授权,企业会话管理加密
Shiro 的官网: http://shiro.apache.org/

D、 Shiro 中的体系的组成

在这里插入图片描述
Authentication:身份的验证-就是我们平时做的登录

Authorization:授权:赋予角色不同的 菜单功能

Session Management:管理登录用户的信息

Cryptography:加密技术 MD5 加密算法等。。

Web Support:shiro 对 web 项目进行的支持

Caching:缓存 可以安全快速的操作

Concurrency:支持并发多线程的处理

Testing:测试

Run As:可以实现在一个用户允许的前提下,使用另一 个用户访问

Remember Me:记住我

E、 shiro 的架构

在这里插入图片描述
Subject(org.apache.shiro.subject.Subject)当前与软 件进行交互的实体(用户,第三方服务,cron job,等 等)的安全特定“视图”

SecurityManager:SecurityManager 是 Shiro 架构的 心脏。它基本上是一个“保护伞”对象,协调其管理的组 件 以 确 保 它 们 能 够 一 起 顺 利 的 工 作 类 似 于 SpringMVC 中的入口 servlet

Realms:域 Realms 在 Shiro 和你的应用程序的安全数据之间担当 “桥梁”或“连接器”。当它实际上与安全相关的数据如用来执行身份验证(登录)及授权(访问控制)的用户帐 户交互时,Shiro 从一个或多个为应用程序配置的 Realm 中寻找许多这样的东西

Shiro 的环境搭建

使用 shiro 实现登陆的操作
第一步 导包
在这里插入图片描述
第二步:书写shiro.ini文件

[users] 
zs=123 
sxt=root

第三步:书写测试代码

package com.bjsxt.shiro1;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.realm.jdbc.JdbcRealm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;

public class TestA {

    public static void main(String[] args) {


        //[1]解析shiro.ini文件

        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例

        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("zs","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

Shiro 验证时异常分析

在这里插入图片描述
在这里插入图片描述

账户失效异常

DisabledAccountException

竞争次数过多

ConcurrentAccessException

尝试次数过多

ExcessiveAttemptsException

用户名不正确

UnknownAccountException

在这里插入图片描述
凭证(密码)不正确

IncorrectCredentialsException

凭证过期

ExpiredCredentialsException

使用 shiro 做异常处理的时候,尽量把异常信息表示的婉转一点,这 样有助于提升代码的安全性

Shiro–认证流程

A、通过 shiro 相关的 API 创建了 SecurityManager 以及获得 
subject 实例
 
B、封装了 token 信息

C、详细描述 
通过 subject.login(token)进行用户认证 
Subject 接受 token 信息 ,通过 DelegatingSubject 
将 token 委托给 securityManager 完成认证 
securityManager 通过使用 DefaultSecurityManager 
完成相关功能由 DefaultSecurityManager 中的 login 方法完 
成对应的认证在 login 中调用了 
AuthenticatingSecurityManager 
中的 authenticate 方法完成认证 
使用其中的doAuthenticate 获得realms信息如果是单个直接进 
行比较,判断是否成功,如果是多个 raalm 需要使用验证策略完成 
对应的认证工作

shiro 中的 JDBCRealm

在这里插入图片描述
注意:表名列名要相对应

shiro-jdbc.ini

[main]
dataSou=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou.driverClass=com.mysql.jdbc.Driver
dataSou.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro
dataSou.user=root
dataSou.password=root

jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSou

securityManager.realm=$jdbcRealm

TestB .java

package com.bjsxt.shiro1;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class TestB {

    public static void main(String[] args) {


        //[1]解析shiro.ini文件

        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro-jdbc.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例

        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("root","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

认证策略

规定了如果有多个数据源的时候应该如何操作

AtLeastOneSuccessfulStrategy
如果一个(或更多)Realm 验证成功,则整体的尝试被认为是成功的。 如果没有一个验证成功, 则整体尝试失败 类似于java 中的 &

FirstSuccessfulStrategy
只有第一个成功地验证的 Realm 返回的信息将被使用。所有进一步的 Realm 将被忽略。如果没有一个验证成功,则整体尝试失败。 类似于java 中的 &&

AllSucessfulStrategy
为了整体的尝试成功,所有配置的 Realm 必须验证成功。如果没有一个验 证成功,则整体尝试失败
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
shiro-jdbc.ini

[main]
#获得数据源A
dataSou=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou.driverClass=com.mysql.jdbc.Driver
dataSou.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro
dataSou.user=root
dataSou.password=root

#配置了jdbcRealmA
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.dataSource=$dataSou


#获得数据源B
dataSou1=com.mchange.v2.c3p0.ComboPooledDataSource
dataSou1.driverClass=com.mysql.jdbc.Driver
dataSou1.jdbcUrl=jdbc:mysql://127.0.0.1:3306/shiro1
dataSou1.user=root
dataSou1.password=root

#配置了jdbcRealmB
jdbcRealm1=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm1.dataSource=$dataSou1


#配置验证器
authenticationStrategy=org.apache.shiro.authc.pam.AllSucessfulStrategy 



#设置securityManager中realm
securityManager.realms=$jdbcRealm,$jdbcRealm1
securityManager.authenticator.authenticationStrategy=$authenticationStrategy

TestA.java

package com.bjsxt.shiro1;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class TestA {

    public static void main(String[] args) {

        /*Realm*/

        //[1]解析shiro.ini文件
        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro-jdbc.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例
        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("sxt","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

在这里插入图片描述
在这里插入图片描述

自定义 Realm

[1] 为什么使用自定义 Realm
我们使用 JDBCRealm 的时候发现,shiro 的底层自己封装了数据库 表的名称和字段的名称,这样就造成了使用起来非常不方便

[2] 解决方案
自定义 Realm 我们如果自己定义 realm 的话,可以实现这个接口

[3] 步骤

新建表:admin
在这里插入图片描述
UserRealm.java

package com.bjsxt.shiro2;

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 java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserRealm  extends AuthorizingRealm {

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //System.out.println(authenticationToken.getPrincipal());

        try {
            Class.forName("com.mysql.jdbc.Driver");

            Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");


            PreparedStatement prepareStatement = conn.prepareStatement("select  pwd  from  admin  where  uname =? ");

            prepareStatement.setObject(1,authenticationToken.getPrincipal());

            ResultSet rs = prepareStatement.executeQuery();

            while (rs.next()){

                SimpleAuthenticationInfo  info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),rs.getString("pwd"),"userRealm");

                return   info;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
     //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

shiro-jdbc2.ini

[main]
#设置securityManager中realm
userRealm=com.bjsxt.shiro2.UserRealm
securityManager.realms=$userRealm

TestB.java

package com.bjsxt.shiro2;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class TestB {

    public static void main(String[] args) {

        /*Realm*/

        //[1]解析shiro.ini文件
        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro-jdbc2.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例
        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("root","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

在这里插入图片描述

散列算法(算法加密)

A、 在身份认证的过程中往往都会涉及到加密,如果不加密,这个时 候信息就会非常的不安全,shiro 中提供的算法比较多 如 MD5 SHA 等

使用 MD5 进行 ‘’1111 加密 b59c67bf196a4758191e42f76670ceba
在这里插入图片描述
进行加盐操作
1111+姓名=
在这里插入图片描述
B、实现的案例

TestDemo .java

package com.bjsxt.shiro3;

import org.apache.shiro.crypto.hash.Md5Hash;

public class TestDemo   {


    public static void main(String[] args) {


        //使用MD5加密
        Md5Hash  md5=new Md5Hash("1111");

        System.out.println("1111=="+md5);

        //加盐
        md5=new Md5Hash("1111","sxt");

        System.out.println("1111=="+md5);

        //迭代次数
        md5=new Md5Hash("123","sxt",2);

        System.out.println("1111=="+md5);
    }
}

在这里插入图片描述
shiro-jdbc3.ini

[main]
#设置securityManager中realm
credentialsMatcher=org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=md5
credentialsMatcher.hashIterations=2

userRealm=com.bjsxt.shiro3.UserRealm
userRealm.credentialsMatcher=$credentialsMatcher
securityManager.realms=$userRealm

UserRealm .java

package com.bjsxt.shiro3;

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 org.apache.shiro.util.ByteSource;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserRealm  extends AuthorizingRealm {

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        try {
            Class.forName("com.mysql.jdbc.Driver");

            Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");

            PreparedStatement prepareStatement = conn.prepareStatement("select  uname,pwd  from  admin ");

            ResultSet rs = prepareStatement.executeQuery();
            System.out.println(rs);
            while (rs.next()){
                SimpleAuthenticationInfo  info=new SimpleAuthenticationInfo(rs.getString("uname"),rs.getString("pwd"), ByteSource.Util.bytes("sxt"),"userRealm");
                return   info;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
     //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

TestB.java

package com.bjsxt.shiro3;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class TestB {

    public static void main(String[] args) {

        /*Realm*/

        //[1]解析shiro.ini文件
        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro-jdbc3.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例
        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("root","111");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

在这里插入图片描述

授权

授权:给身份认证通过的任授予某些资源的访问权限
权限的粒度 粗粒度 细粒度

粗粒度
User 具有 CRUD 的操作 通常指的是表的操作

细粒度
只允许查询 id=1 的用户 使用业务代码实现

Shiro 的授权是粗粒度

角色:角色就是权限的集合

Shiro 中代码的实现

shiro.ini

#指定具体的用户
[users]
zs=123,role1,role2
sxt=root

#角色的定义
[roles]
role1=add,update,delete
role2=find

#给对象中的属性赋值
#[main]

TestA.java

package com.bjsxt.shiro1;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

import java.util.Arrays;

public class TestA {

    public static void main(String[] args) {
        //[1]解析shiro.ini文件
        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例
        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("zs","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

        } catch (IncorrectCredentialsException e) {
            System.out.println("登录失败");
        }


        //授权的查询

        //基于角色的授权
        boolean flag = subject.hasRole("role1");
        //System.out.println(flag);

        //判断是否具有多个角色
        boolean[] booleans = subject.hasRoles(Arrays.asList("role1", "role3"));

        /*for(Boolean b:booleans){

            System.out.println(b);
        }*/

        //可以使用checkRole判断指定用户是否具有对应角色
        //如果指定用户下没有对应的角色就会抛出异常UnauthorizedException
       /* subject.checkRole("role3");

        subject.checkRoles("role1","role2");*/


       //基于资源的授权
        boolean flag2 = subject.isPermitted("iii");

        //System.out.println(flag2);

        //判读是否具有多个资源
        boolean permittedAll = subject.isPermittedAll("add", "oo", "ii");

        //通过checkPermission 进行判断指定用户下是否有指定的资源
        //如果没有就会抛出UnauthorizedException
        subject.checkPermission("uu");

        subject.checkPermissions("ii","ooo","add");

    }
}

Shiro 中的授权检查的 3 种方式
A、 编程式
TestA.java

B、 注解式

package com.bjsxt.shiro1;

import org.apache.shiro.authz.annotation.RequiresRoles;

public class Role {
    
    @RequiresRoles("管理员")
    public void aa(){
        
    }

}

C、 标签配置

<shiro:hasPermission name="add">
	 <a>添加操作</a> 
</shiro:hasPermission>

自定义 Realm 实现授权

我们仅仅通过配置文件指定授权是非常的不灵活的,在实际的应用中 我们是将用户的信息和合权限信息保存到数据库中,我们是从数据库 中获得用户的信息 ,使用 JDBCRealm 进行授权 。使用 JDBCRealm 操 作的时候也不是很灵活。所以我们一般使用自定义 Realm 实现授权。
shiro-jdbc.ini

[main]
#设置securityManager中realm
userRealm=com.bjsxt.shiro.UserRealm
securityManager.realms=$userRealm

UserRealm.java

package com.bjsxt.shiro;

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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.List;

public class UserRealm  extends AuthorizingRealm {

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        //System.out.println(authenticationToken.getPrincipal());

        try {
            Class.forName("com.mysql.jdbc.Driver");

            Connection conn = DriverManager.getConnection("jdbc:mysql://127.0.0.1:3306/shiro", "root", "root");


            PreparedStatement prepareStatement = conn.prepareStatement("select  pwd  from  admin  where  uname =? ");

            prepareStatement.setObject(1,authenticationToken.getPrincipal());

            ResultSet rs = prepareStatement.executeQuery();

            while (rs.next()){

                SimpleAuthenticationInfo  info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),rs.getString("pwd"),"userRealm");

                return   info;

            }
        } catch (Exception e) {
            e.printStackTrace();
        }


        return null;
    }

     //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String username = principalCollection.getPrimaryPrincipal().toString();

        //获得username  然后去数据库查询这个用户对应的角色,在根据角色查询出指定角色下对应的菜单,
        //返回给指定角色下的所有菜单--List集合
        System.out.println("username="+username);

        //模拟数据库查的菜单
        List<String>  list =new ArrayList<>();
        list.add("updateUser");
        list.add("addUser");
        list.add("deleteUser");

        SimpleAuthorizationInfo  simpleAuthorizationInfo=new SimpleAuthorizationInfo();

        for(String   l:list){
            simpleAuthorizationInfo.addStringPermission(l);
        }
       return simpleAuthorizationInfo;
    }
}

TestB.java

package com.bjsxt.shiro;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;

public class TestB {

    public static void main(String[] args) {

        /*Realm*/

        //[1]解析shiro.ini文件
        Factory<SecurityManager>  factory =new IniSecurityManagerFactory("classpath:shiro-jdbc2.ini");

        //[2]通过SecurityManager工厂获得SecurityManager实例
        SecurityManager securityManager = factory.getInstance();

        //[3]把SecurityManager对象设置到运行环境中
        SecurityUtils.setSecurityManager(securityManager);

        //[4]通过SecurityUtils获得主体subject
        Subject subject = SecurityUtils.getSubject();

        //[5]书写自己输入的账号和密码---相当于用户自己输入的账号和密码
        //我们拿着自己书写用户名密码去和shiro.ini 文件中的账号密码比较
        UsernamePasswordToken  token =new UsernamePasswordToken("root","123");

        try {
            //[6]进行身份的验证
            subject.login(token);

            //[7]通过方法判断是否登录成功

            if(subject.isAuthenticated()){
                System.out.println("登录成功");

                //授权的校验
                System.out.println("是否存在该菜单:"+subject.isPermitted("updateUser2123"));

            }
        } catch (IncorrectCredentialsException e) {

            System.out.println("登录失败");


        }catch (UnknownAccountException e){

            System.out.println("用户名不正确");
        }
    }
}

SSM 整合 Shiro

【A】 导包
在这里插入图片描述
【B】 书写 web.xm

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
		  http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
           version="2.5">

     <!--解析Springmvc.xml-->
    <servlet>
        <servlet-name>springmvc</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>

        <!--初始化参数  contextConfigLocation-->
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>classpath:springmvc.xml</param-value>
        </init-param>

    </servlet>

    <servlet-mapping>
        <servlet-name>springmvc</servlet-name>
        <!-- / 除了jsp以外的所有资源都可以访问指定的servlet-->
        <url-pattern>/</url-pattern>
    </servlet-mapping>

    <!--解析applicationContext-*.xml文件-->
     <context-param>
         <param-name>contextConfigLocation</param-name>
         <param-value>classpath:applicationContext-*.xml</param-value>
     </context-param>
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <!--注册了DelegatingFilterProxy 使用代理把servlet容器中fiter和Spring 中的bean进行连接-->
    <filter>
        <filter-name>shiro</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>

        <!--设置为truez之后可以使用过滤器中初始化 销毁等方法-->
        <init-param>
            <param-name>targetFilterLifecycle</param-name>
            <param-value>true</param-value>
        </init-param>

        <!--给注册了的bend起名称-->
        <init-param>
            <param-name>targetBeanName</param-name>
            <param-value>shiroFilter</param-value>
        </init-param>

    </filter>
 
    <filter-mapping>
        <filter-name>shiro</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>
    
</web-app>

【C】书写了applicationContext-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:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/tx
        http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!--[A]注册凭证匹配器-->
    <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">

          <property name="hashAlgorithmName" value="md5"></property>

          <property name="hashIterations" value="2"></property>

    </bean>

    <!--[B]注册自定义Realm-->
    <bean id="userRealm" class="com.bjsxt.realm.UserRealm">

        <property name="credentialsMatcher"  ref="credentialsMatcher"></property>

    </bean>

    <!--[C]注册securityManager-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

        <property name="realms" ref="userRealm"></property>
    </bean>

    <!--[D]注册ShiroFilterFactoryBean对象-->
    <!-- bean对象中的id名称必须和web.xml中targetBeanName保持一致-->

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        <property name="securityManager"  ref="securityManager"></property>

        <property name="loginUrl" value="/login"></property>

        <property name="successUrl" value="/success.jsp"></property>

        <property name="unauthorizedUrl" value="/error.jsp"></property>

        <!--设置过滤器链的属性  authc拦截指定路径 anon放行资源  -->
        <property name="filterChainDefinitions">

            <value>
                 /login=authc
                 <!--配置退出的过滤器 如果没有配置退出的页面,默认是退到项目的默认网页中 index.jsp /index.html-->
                 /loginOut=logout
                 
                  /**=anon
            </value>
        </property>
    </bean>
    <!--配置退出的过滤器-->
    <bean id="logout" class="org.apache.shiro.web.filter.authc.LogoutFilter">
    	<property name="redirectUrl" value="login.jsp"></property>
    </bean>
        <!--表单过滤器-->

      <bean id="authc" class="org.apache.shiro.web.filter.authc.FormAuthenticationFilter">

          <property name="usernameParam" value="uname"></property>

          <property name="passwordParam" value="pwd"></property>

          <property name="rememberMeParam" value="rm"></property>


      </bean>
</beans>

在这里插入图片描述
【D】创建实体

package com.bjsxt.pojo;

import java.io.Serializable;

public class Admin implements Serializable {


    private   String   username;

    private   String   password;

    private    String  salt;

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public Admin(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public Admin(){}

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

【E】自定义 realm

package com.bjsxt.realm;

import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
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 org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserRealm extends AuthorizingRealm {

        @Autowired
        AdminService  adminService;

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        Admin admin = adminService.findPwd(authenticationToken.getPrincipal().toString());
        if(admin!=null){
            SimpleAuthenticationInfo  info=new SimpleAuthenticationInfo(authenticationToken.getPrincipal(),admin.getPassword(), ByteSource.Util.bytes(admin.getSalt()),"userRealm");
            return   info;
        }
        return null;
    }
     //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
}

【F】书写业务层

package com.bjsxt.service;

import com.bjsxt.pojo.Admin;

public interface AdminService {

    //用户的登陆
    public Admin  login(String uname, String pwd);

    //获得用户密码 延迟操作
    public   Admin   findPwd(String   username);
}

package com.bjsxt.service.impl;

import com.bjsxt.mapper.AdminMapper;
import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service("admins")
public class AdminServiceImpl implements AdminService {

    @Autowired
    AdminMapper  adminMapper;

    @Override
    public Admin login(String uname, String pwd) {

        return adminMapper.selectOne(uname, pwd);
    }

    @Override
    public Admin findPwd(String username) {
        return adminMapper.selectPwd(username);
    }
}

【G】书写控制层

package com.bjsxt.controller;

import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.lang.model.element.UnknownAnnotationValueException;
import javax.servlet.http.HttpServletRequest;

@Controller
public class AdminController {

    @RequestMapping("login")
    public    String   login(HttpServletRequest req){
        //查看具体的异常信息,获得一场的信息名称
        Object ex = req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
     if(UnknownAccountException.class.getName().equals(ex)){
            req.setAttribute("msg","用户名错误");
        }else  if(IncorrectCredentialsException.class.getName().equals(ex)){
            req.setAttribute("msg","凭证不正确");

        }else{
            req.setAttribute("msg","未知异常");
        }
        return   "/error.jsp";
    }
}

页面:
error.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

${msg}

</body>
</html>

index.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <base href="<%=request.getContextPath()+"/"%>">
  </head>
  <body>
  $END$
  </body>
</html>

login.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登陆</title>
    <base href="<%=request.getContextPath()+"/"%>">
</head>
<body>

<h3>用户登陆</h3>
<form action="login" method="post">

    <p>
        用户名:<input type="text" name="username"/>${msg}
    </p>
    <p>
        密码:<input type="text" name="password"/>
    </p>
    <p>
        <input type="submit" value="提交"/>
    </p>

</form>

</body>
</html>

success.jsp

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>成功页面</title>
    <base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>成功页面</h3>
<h4 style="float: right"><a href="loginOut">退出</a></h4>
<h3>sessionID:<%=session.getid()%></h3>
</body>
</html>

shiro实现授权

准备:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/**zs登录成功看到的菜单**/
SELECT mmid FROM 'role_menu' WHERE rid=2
SELECT * FROM menu WHERE mmin IN(SELECT mmid FROM 'role_menu' WHERE rid=2) AND pid=2

在这里插入图片描述
实现步骤

添加实体

Admin

package com.bjsxt.pojo;

import java.io.Serializable;
import java.util.List;

public class Admin implements Serializable {


    private   String   username;

    private   String   password;

    private    String  salt;

    private     int  rid;


    //保存菜单的集合
    private List<Menu> list;

    //保存权限的集合
    private    Role      role;

    public Role getRole() {
        return role;
    }

    public void setRole(Role role) {
        this.role = role;
    }

    public List<Menu> getList() {
        return list;
    }

    public void setList(List<Menu> list) {
        this.list = list;
    }

    public int getRid() {
        return rid;
    }

    public void setRid(int rid) {
        this.rid = rid;
    }

    public String getSalt() {
        return salt;
    }

    public void setSalt(String salt) {
        this.salt = salt;
    }

    public Admin(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public Admin(){}

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

Menu

package com.bjsxt.pojo;

import java.io.Serializable;
import java.util.List;

public class Menu implements Serializable {


    private   Integer  mmid;

    private    String   mname;

    private   String   url;

    private   int  pid;


    private List<Menu> list;

    public List<Menu> getList() {
        return list;
    }

    public void setList(List<Menu> list) {
        this.list = list;
    }

    public Menu(Integer mmid, String mname, String url, int pid) {
        this.mmid = mmid;
        this.mname = mname;
        this.url = url;
        this.pid = pid;
    }

    public Menu(){}

    public Integer getMmid() {
        return mmid;
    }

    public void setMmid(Integer mmid) {
        this.mmid = mmid;
    }

    public String getMname() {
        return mname;
    }

    public void setMname(String mname) {
        this.mname = mname;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public int getPid() {
        return pid;
    }

    public void setPid(int pid) {
        this.pid = pid;
    }

    @Override
    public String toString() {
        return "Menu{" +
                "mmid=" + mmid +
                ", mname='" + mname + '\'' +
                ", url='" + url + '\'' +
                ", pid=" + pid +
                '}';
    }
}

Role

package com.bjsxt.pojo;

import java.io.Serializable;

public class Role implements Serializable {


    private    int  rid;

    private   String   rname;

    public Role(int rid, String rname) {
        this.rid = rid;
        this.rname = rname;
    }

    public Role(){}

    public int getRid() {
        return rid;
    }

    public void setRid(int rid) {
        this.rid = rid;
    }

    public String getRname() {
        return rname;
    }

    public void setRname(String rname) {
        this.rname = rname;
    }

    @Override
    public String toString() {
        return "Role{" +
                "rid=" + rid +
                ", rname='" + rname + '\'' +
                '}';
    }
}

添加Mapper
Menu

package com.bjsxt.mapper;

import com.bjsxt.pojo.Menu;

import java.util.List;

public interface MenuMapper {


    //菜单的查询
    public List<Menu>   selectMore(int rid,int pid);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjsxt.mapper.MenuMapper">

    <select id="selectMore" resultType="menu">

        SELECT  *  FROM   menu   WHERE   mmid  IN (SELECT   mmid    FROM  role_menu  WHERE   rid =#{0} ) AND  pid =#{1}

    </select>
</mapper>

Admin

package com.bjsxt.mapper;

import com.bjsxt.pojo.Admin;

public interface AdminMapper {

    //查询单个操作
    public Admin  selectOne(String uname, String pwd);


    public    Admin   selectPwd(String   username);

}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjsxt.mapper.AdminMapper">

    <select id="selectOne" resultType="admin">

      SELECT   *  from  admin  where  username =#{param1}  and  password =#{param2}

    </select>

    <select id="selectPwd" resultType="admin">


        SELECT   *  from  admin  where  username =#{param1}
    </select>

</mapper>

Role

package com.bjsxt.mapper;

import com.bjsxt.pojo.Role;

public interface RoleMapper {

    //查询角色的名称
    public Role   selectOne(int  rid);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.bjsxt.mapper.RoleMapper">

    <select id="selectOne" resultType="role">

          SELECT   *  from  role  where  rid =#{0}

    </select>

</mapper>

添加service
Menu

package com.bjsxt.service;

import com.bjsxt.pojo.Menu;

import java.util.List;

public interface MenuService {

    //查询指定角色的菜单
    public List<Menu>   findMoreMenus(int  rid);

}
package com.bjsxt.service.impl;

import com.bjsxt.mapper.MenuMapper;
import com.bjsxt.pojo.Menu;
import com.bjsxt.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class MenuServiceImpl  implements MenuService {


    @Autowired
    MenuMapper  menuMapper;

    @Override
    public List<Menu> findMoreMenus(int rid) {

        //指定角色下的一级菜单
        List<Menu> list = menuMapper.selectMore(rid, 0);


        for(Menu  menu:list){

            //一级菜单的mmid
            Integer mmid = menu.getMmid();

            //指定一级菜单下对应的二级菜单
            List<Menu> list2 = menuMapper.selectMore(rid, mmid);

            //把二级菜单保存到指定的一级菜单对象中
            menu.setList(list2);
        }
        return list;
    }
}

Admin

package com.bjsxt.service.impl;

import com.bjsxt.mapper.AdminMapper;
import com.bjsxt.mapper.RoleMapper;
import com.bjsxt.pojo.Admin;
import com.bjsxt.pojo.Menu;
import com.bjsxt.service.AdminService;
import com.bjsxt.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("admins")
public class AdminServiceImpl implements AdminService {

    @Autowired
    AdminMapper  adminMapper;

    @Autowired
    MenuService  menuService;

    @Autowired
    RoleMapper  roleMapper;

    @Override
    public Admin login(String uname, String pwd) {

        return adminMapper.selectOne(uname, pwd);
    }

    @Override
    public Admin findPwd(String username) {

        Admin admin = adminMapper.selectPwd(username);


        List<Menu> list = menuService.findMoreMenus(admin.getRid());

        //把菜单保存到执行的admin对象中
        admin.setList(list);
        //把用户的身份保存admin中
        admin.setRole(roleMapper.selectOne(admin.getRid()));

        return  admin;
    }
}
package com.bjsxt.service;

import com.bjsxt.pojo.Admin;

public interface AdminService {

    //用户的登陆
    public Admin  login(String uname, String pwd);

    //获得用户密码 颜值操作
    public   Admin   findPwd(String   username);
}

添加realm【授权】

package com.bjsxt.realm;

import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
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.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

public class UserRealm extends AuthorizingRealm {

        @Autowired
        AdminService  adminService;

    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        Admin admin = adminService.findPwd(authenticationToken.getPrincipal().toString());
        if(admin!=null){
            SimpleAuthenticationInfo  info=new SimpleAuthenticationInfo(admin,admin.getPassword(), ByteSource.Util.bytes(admin.getSalt()),"userRealm");
            return   info;
        }
        return null;
    }
     //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        Admin   admin = (Admin) principalCollection.getPrimaryPrincipal();

        SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();


        //把角色的名称保持到SimpleAuthorizationInfo
        info.addRole(admin.getRole().getRname());

        return info;
    }
}

添加controller

package com.bjsxt.controller;

import com.bjsxt.pojo.Admin;
import com.bjsxt.service.AdminService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.lang.model.element.UnknownAnnotationValueException;
import javax.servlet.http.HttpServletRequest;

@Controller
public class AdminController {


    @RequestMapping("findMoreMenus")
    public   String   findMoreMenus(HttpServletRequest  req){

        //获得验证成功以后的admin 对象
        Admin admin = (Admin) SecurityUtils.getSubject().getPrincipal();

       req.setAttribute("list",admin.getList());

       return  "/success.jsp";

    }

    @RequestMapping("login")
    public    String   login(HttpServletRequest req){

        //查看具体的异常信息,获得一场的信息名称
        Object ex = req.getAttribute(FormAuthenticationFilter.DEFAULT_ERROR_KEY_ATTRIBUTE_NAME);
        if(UnknownAccountException.class.getName().equals(ex)){
            req.setAttribute("msg","用户名错误");
        }else  if(IncorrectCredentialsException.class.getName().equals(ex)){
            req.setAttribute("msg","凭证不正确");
        }else{
            req.setAttribute("msg","未知异常");
        }
        return   "/error.jsp";
    }
}

页面
error

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>

${msg}

</body>
</html>

index

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
  <head>
    <title>$Title$</title>
    <base href="<%=request.getContextPath()+"/"%>">
  </head>
  <body>
  $END$
  </body>
</html>

login

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登陆</title>
    <base href="<%=request.getContextPath()+"/"%>">
</head>
<body>

<h3>用户登陆</h3>
<form action="login" method="post">

    <p>
        用户名:<input type="text" name="uname"/>${msg}
    </p>
    <p>
        密码:<input type="text" name="pwd"/>
    </p>
   
    <p>
        <input type="submit" value="提交"/>
    </p>

</form>

</body>
</html>

success

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<%@taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <title>成功页面</title>
    <base href="<%=request.getContextPath()+"/"%>">
</head>
<body>
<h3>成功页面</h3>

<h4 style="float: right"><a href="loginOut">退出</a> </h4>

<h3>sessionID:<%=session.getId()%></h3>

<hr/>
<shiro:hasRole name="学生">

   <h1>查询</h1>
</shiro:hasRole>

<shiro:hasRole name="老师">

    <h1>删除</h1>
</shiro:hasRole>

<shiro:hasRole name="管理员">

    <h1>查询</h1>
    <h1>删除</h1>
    <h1>添加</h1>
</shiro:hasRole>
<hr/>
<c:forEach items="${list}" var="menu">
      <h4>${menu.mname}</h4>
      <c:forEach items="${menu.list}" var="menu2">
           &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
           <a href="${menu2.url}">${menu2.mname}</a><br/>
      </c:forEach>
</c:forEach>
</body>
</html>

在这里插入图片描述
在这里插入图片描述

SessionManager 的管理

设置管理登录5秒后失效
实现步骤

<!--[C]注册securityManager-->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

        <property name="realms" ref="userRealm"></property>

        <property name="sessionManager" ref="sessionManager"></property>
    </bean>
    
    
    <!--配置会话管理器-->
      <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">

          &lt;!&ndash;单位是毫秒&ndash;&gt;
          <property name="globalSessionTimeout"  value="5000"></property>

          &lt;!&ndash;删除无效的session &ndash;&gt;
          <property name="deleteInvalidSessions" value="true"></property>

      </bean>

RememberMe 记住我

A、 所有的实体类 都必须实现序列化接口
同上
B、 更改 JSP 页面
login

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>用户登陆</title>
    <base href="<%=request.getContextPath()+"/"%>">
</head>
<body>

<h3>用户登陆</h3>
<form action="login" method="post">

    <p>
        用户名:<input type="text" name="uname"/>${msg}
    </p>
    <p>
        密码:<input type="text" name="pwd"/>
    </p>
    <p>
        记住我:<input type="checkbox"  checked  name="rm"/>
    </p>
    <p>
        <input type="submit" value="提交"/>
    </p>

</form>

</body>
</html>

C、 配置 bend 对象

<!--设置过滤器链的属性  authc拦截指定路径 anon放行资源  -->
        <property name="filterChainDefinitions">
            <value>
                 /login=authc
                <!--配置退出的过滤器  如果没有配置退出的页面,默认是退到项目的默认网页中 index.jsp /index.html-->
                /loginOut=logout

                <!--记住我的  路径-->
                /findMoreMenus=user

                /**=anon
            </value>
        </property>


  <!--注册SimpleCookie-->
    <bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">

        <!--设置cookie 的名称-->
        <property name="name" value="rm"></property>

        <!--设置cookie的有效时间  单位秒  7天免登陆-->
        <property name="maxAge" value="604800"></property>

    </bean>

    <!--注册rememberMeManger-->

    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">

        <property name="cookie" ref="simpleCookie"></property>

    </bean>

D、测试

在这里插入图片描述
项目练习源码:https://gitee.com/cutelili/shiro-security-framework

设计模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值