栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Shiro安全框架

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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

        

        //[1]解析shiro.ini文件
        Factory  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) {

        

        //[1]解析shiro.ini文件
        Factory  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) {

        

        //[1]解析shiro.ini文件
        Factory  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  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"));

        

        //可以使用checkRole判断指定用户是否具有对应角色
        //如果指定用户下没有对应的角色就会抛出异常UnauthorizedException
       


       //基于资源的授权
        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、 标签配置


	 添加操作 

自定义 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  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) {

        

        //[1]解析shiro.ini文件
        Factory  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




     
    
        springmvc
        org.springframework.web.servlet.DispatcherServlet

        
        
            contextConfigLocation
            classpath:springmvc.xml
        

    

    
        springmvc
        
        /
    

    
     
         contextConfigLocation
         classpath:applicationContext-*.xml
     
    
        org.springframework.web.context.ContextLoaderListener
    
    
    
    
        shiro
        org.springframework.web.filter.DelegatingFilterProxy

        
        
            targetFilterLifecycle
            true
        

        
        
            targetBeanName
            shiroFilter
        

    
 
    
        shiro
        
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 list;

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

    public Role getRole() {
        return role;
    }

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

    public List getList() {
        return list;
    }

    public void setList(List 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 list;

    public List getList() {
        return list;
    }

    public void setList(List 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   selectMore(int rid,int pid);

}





    

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

    

    

          SELECT   *  from  role  where  rid =#{0}

    


添加service
Menu

package com.bjsxt.service;

import com.bjsxt.pojo.Menu;

import java.util.List;

public interface MenuService {

    //查询指定角色的菜单
    public List   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 findMoreMenus(int rid) {

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


        for(Menu  menu:list){

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

            //指定一级菜单下对应的二级菜单
            List 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 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" %>


    Title



${msg}



index

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

  
    $Title$
    ">
  
  
  $END$
  

login

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


    用户登陆
    ">



用户登陆

用户名:${msg}

密码:

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


    成功页面
    ">


成功页面

退出

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


查询

删除

查询

删除

添加


${menu.mname}

       ${menu2.mname}


SessionManager 的管理

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

    

        

        
    
    
    
    
      

          <!–单位是毫秒–">>
          

          <!–删除无效的session –">>
          

      
RememberMe 记住我

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

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


    用户登陆
    ">



用户登陆

用户名:${msg}

密码:

记住我:

C、 配置 bend 对象

        
            
                 /login=authc
                
                /loginOut=logout

                
                /findMoreMenus=user

                /**=anon
            
        


  
    

        
        

        
        

    

    

    

        

    

D、测试


项目练习源码:https://gitee.com/cutelili/shiro-security-framework

设计模式

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/424235.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号