Shiro权限验证详细教程

一、Shiro介绍

1、可从本教程中明白以下几个知识点:

  • 认识Shiro的整体架构和各组件的概念;
  • Shiro认证、授权过程;
  • Shiro自定义Realm.

2、Shiro简介

Shiro是Apache强大灵活的开源的安全框架,有认证、授权、企业会话管理、安全加密、缓存管理等功能。

Shiro和Spring Security相比较;Shiro更加简单方便、并且可脱离Spring,Spring Security比较笨重复杂,不可脱离Spring。

3、Shiro架构图

详细图如上面所示:在这里就不介绍具体每个组件了,我会在以下4个实例代码中详细说明;

4、项目中用到的依赖:

  

添加完依赖,以下所有实例都可以直接运行。

二、第一个实例(初识Shiro认证/授权)

1、Shiro认证/授权过程:代码有详解

认证原理:创建SecurityManager---->主体提交认证请求----->提交到SecurityManager认证---->SecurityManager认证是由Authenticator进行认证---->Authenticator认证需要通过Realm验证用户数据。

授权原理:创建SecurityManager---->主体授权---->提交到SecurityManager授权---->SecurityManager授权是有Authorizer进行授权---->Realm获取角色权限数据

public class AuthenticationTest {
    SimpleAccountRealm simpleAccountRealm=new SimpleAccountRealm();
    @Before
    public void getAccount()
    {
        //方便测试  新增用户和角色权限
        simpleAccountRealm.addAccount("quentin","123456","admin");
    }
    @Test
    public void AuthenticationTest()
    {
        //1、创建SecurtyManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        defaultSecurityManager.setRealm(simpleAccountRealm);

        //2、主体认证/授权
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject=SecurityUtils.getSubject();//获得当前正在执行程序的用户

        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("quentin","123456");
        //3、login()主体认证请求,里面封装好的不用管,它是由SecurityManager认证->Authenticate认证->Realm验证组成,这样就可以实现认证。
        subject.login(usernamePasswordToken);
        System.out.println("isAuthen:"+subject.isAuthenticated());
        //3、checkRole()主体授权请求,里面封装好的不用管,它是由SecurityManager授权->Authenticate授权->Realm获取角色权限组成,这样就可以实现授权功能。
        subject.checkRole("admin");
    }
}

运行结果:

  

当验证不通过会抛出异常,没有权限也会抛出异常!!

 所以,总结一下整个流程,以认证为例:就是在我们调用Subject的login()方法之后,可以看到我传入的是用户的token(里面的实际原理不用管,其实就是第一第二步它经历过一系列的步骤,它调用了Realm中的doGetAuthenticationInfo(token)方法)。

三、第二个实例(IniRealm实例讲解)

 介绍:通过加载.ini文件生成realm对象来验证

1、在resourses中建立user.ini文件,内容如下:

[users]
quentin=123456,admin
[roles]
admin=user:delete,user:update

设置用户名"quentin",密码是"123456",“admin”角色,"admin"拥有“user:delete、user:update”权限。

2、实例文件代码如下:

public class IniRealmTest {

    @Test
    public void IniRealmTest()
    {
        IniRealm iniRealm=new IniRealm("classpath:user.ini");  //配置user.ini文件(账号和权限等信息)

        //1、创建SecurtyManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        defaultSecurityManager.setRealm(iniRealm);//设置Realm

        //2、主体认证/授权请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject=SecurityUtils.getSubject();

        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("quentin","123456");
        subject.login(usernamePasswordToken);
        System.out.println("isAuth:"+subject.isAuthenticated());//是否认证

        //判断是否授权等
        subject.checkRole("admin");//是否有角色权限
        subject.checkPermission("user:delete");//是否有删除权限
    }
}

运行结果:

  

说明认证通过(用户名密码正确),但是跑出没有权限异常(因为admin没有user:deleteall全选)。

四、第三个实例(JdbcRealm实例讲解)

  介绍:通过获取数据库用户数据来验证

1、实例代码如下:

public class JdbcRealmTest {

    DruidDataSource dataSource=new DruidDataSource();
    {
        dataSource.setUrl("jdbc:mysql://10.0.92.23:3306/test");
        dataSource.setUsername("root");
        dataSource.setPassword("123");
    }

    @Test
    public void JdbcRealmTest()
    {
        JdbcRealm jdbcRealm=new JdbcRealm();
        jdbcRealm.setDataSource(dataSource);

        String sql="select password from user where name=?";
        jdbcRealm.setAuthenticationQuery(sql);    //查询认证语句
        String sqlrole="select rolename from role where name=?";
        jdbcRealm.setUserRolesQuery(sqlrole);     //查询角色权限语句

        //1、创建SecurtyManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        defaultSecurityManager.setRealm(jdbcRealm);

        //2、主体认证/授权请求
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        Subject subject=SecurityUtils.getSubject();

        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("aaa","dfdf");
        subject.login(usernamePasswordToken);

        System.out.println("isAuth:"+subject.isAuthenticated());//判断是有认证

        subject.checkRole("admin");//是否有权限
    }
}

运行结果也一样就不演示了。其实JdbcRealm里面也提供了默认的sql语句,但是考虑到查询不一样,所以需要单独编写。

五、第四个实例(自定义Realm及Shiro加密)

1、自定义Realm,分为doGetAuthenticationInfo()认证 和 doGetAuthorizationInfo()授权信息两部分,注意代码注释:

代码如下:

//自定义Realm,代码如下:
public class CustomerRealm extends AuthorizingRealm {

    //继承父类AuthorizingRealm将获取Subject相关信息分成两步:获取身份验证信息(doGetAuthenticationInfo)及授权信息(doGetAuthorizationInfo);

    // 原理!!!!!!!!!
    /* doGetAuthenticationInfo获取身份验证相关信息:首先根据传入的用户名获取User信息;
    * 然后如果user为空,那么抛出没找到帐号异常UnknownAccountException;如果user找到但锁定了抛出锁定异常LockedAccountException;
    * 最后生成AuthenticationInfo信息,交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配,如果不匹配将抛出密码错误异常IncorrectCredentialsException;
    * 另外如果密码重试此处太多将抛出超出重试次数异常ExcessiveAttemptsException;
    * 在组装SimpleAuthenticationInfo信息时,需要传入:身份信息(用户名)、凭据(密文密码)、盐(username+salt),CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。
    * */

    @Override
    //用于当前用户验证。认证login()方法执行会自动调用
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //1、从主体传过来的认证信息中,获取用户名
        String UserName=(String)token.getPrincipal();  //        getPrincipal();身份 | getCredentials();凭据

        //2、通过用户名从数据库中获取密码凭证
        String Password=getPasswordByUsername(UserName);
        if(Password==null)
        {
            return null;
        }
        //组装SimpleAuthenticationInfo信息,(用户名、密文密码、盐)
        SimpleAuthenticationInfo simpleAuthenticationInfo=new SimpleAuthenticationInfo("quentin",Password,"customerReal");
        simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("salt"));  //将盐注册到信息中去

        return simpleAuthenticationInfo;
    }

    //方便测试 设置用户数据
    Map<String,String> userMap=new HashMap<String, String>(16);
    {
        //将带盐"salt"也一起加密
        Md5Hash passMD5=new Md5Hash("123456","salt");
        userMap.put("quentin",passMD5.toString());
        super.setName("customerReal");
    }
    private String getPasswordByUsername(String userName) {
        return userMap.get(userName);
    }

    //----------------------------------------------------------------以上是认证,以下是授权------------------------------------------------------------------------------------------------------

    //doGetAuthorizationInfo获取授权信息:PrincipalCollection是一个身份集合,因为我们现在就一个Realm,所以直接调用getPrimaryPrincipal得到之前传入的用户名即可;
    // 然后根据用户名调用UserService接口获取角色及权限信息。

    @Override
    //用于当前登录用户授权,用户的角色与权限初始化,授权会自动调用
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //获取用户名
        String UserName=(String)principals.getPrimaryPrincipal();  //getPrimaryPrincipal()得到主要的身份  Set<String> getRealmNames(); //获取所有身份验证通过的Realm名字

        //获取角色和权限信息(一般从数据库或缓存中获取)
        Set<String> setRoles=getRolesByUserName();
        Set<String> setPression=getPressionByUserName();

        //设置SimpleAuthorizationInfo信息,(角色和权限)
        SimpleAuthorizationInfo simpleAuthorizationInfo=new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(setRoles);
        simpleAuthorizationInfo.setStringPermissions(setPression);
        return simpleAuthorizationInfo;
    }

    //方便测试  设置用户权限数据
    private Set<String> getPressionByUserName() {
        Set<String> sets=new HashSet<String>();
        sets.add("user:add");
        sets.add("user:delete");
        sets.add("user:select");
        sets.add("admin:select");
        return sets;
    }

    //方便测试  设置用户角色数据
    private Set<String> getRolesByUserName() {
        Set<String> sets=new HashSet<String>();
        sets.add("admin");
        sets.add("user");
        return sets;
    }

}

2、实例运行代码如下:

public class CustomerRealmTest {

    @Test
    public void CustomerRealmTest()
    {
        //引入自定义Realm
        CustomerRealm customerRealm=new CustomerRealm();

        //创建DefaultSecurityManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        defaultSecurityManager.setRealm(customerRealm);

        //设置算法名称和加密次数
        HashedCredentialsMatcher matcher=new HashedCredentialsMatcher();
        matcher.setHashAlgorithmName("md5");
        matcher.setHashIterations(1);
        customerRealm.setCredentialsMatcher(matcher);

        //主体认证,得到SecurityManager实例 并绑定给SecurityUtils
        SecurityUtils.setSecurityManager(defaultSecurityManager);

        //得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
        Subject subject=SecurityUtils.getSubject();
        UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken("quentin","123456");

        //登录,即身份验证
        subject.login(usernamePasswordToken);
        System.out.println("isAuth:"+subject.isAuthenticated());

        subject.checkRole("admin");
        subject.checkPermission("admin:select");

    }
}

运行结果:

  

单独解释下Shiro加密:

在自定义Realm文件中

Md5Hash passMD5=new Md5Hash("123456","salt");
userMap.put("quentin",passMD5.toString());
//由上面代码也能看到解释,其实就是将带盐"salt"也一起加密,作为身份验证的密码信息+
simpleAuthenticationInfo.setCredentialsSalt(ByteSource.Util.bytes("salt"));  //将盐注册到信息中去//将盐"salt"注册到信息中去验证=这样就更加安全。

通过上面4个实例,动手敲一敲,相信你们都能快速了解Shiro认证授权原理了。
 

原文地址:https://www.cnblogs.com/qiujianfeng/p/10274161.html

时间: 2024-11-22 22:53:57

Shiro权限验证详细教程的相关文章

Shiro权限验证代码记录,正确找到shiro框架在什么地方做了权限识别

权限验证方式的验证代码: org.apache.shiro.web.servlet.AdviceFilter这个类是所有shiro框架提供的默认权限验证实例类的父类 验证代码: public void doFilterInternal(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException { Exception exception = nu

shiro 权限验证 AuthorizingRealm doGetAuthorizationInfo

先放代码: https://git.oschina.net/alexgaoyh/alexgaoyh.git 今天在敲代码的过程中,突然发现之前整合的shiro权限框架有问题,doGetAuthorizationInfo() 方法一直没有被调用,后来发现, 1:  doGetAuthorizationInfo()方法可以理解为是权限验证, 2: doGetAuthenticationInfo(  AuthenticationToken token)  理解为登陆验证. 两者是不一样的: 登陆验证:

关于postman与shiro权限验证问题

作为一个java的开发小白 , 写完一个web方法测试是必不可少的 , 只有测试号没问题的方法给别人时 ,别人才不知道你是小白 , 要不然很尴尬的 .新手入坑的测试工具是postman .这个工具用起来还可以 , 这里就不做新手入坑介绍了 , 就说说常用的一个功能吧!!!就是postman关于shiro验证的问题.     shiro的权限控制很简单,是现在常用验证机制之一,但是有些一些方法常常需要登录后才能进行测试,要不然shiro不让你过去,那怎么办呢?一般开发中的方法是 , 加一个配置文件

简单两步快速实现shiro的配置和使用,包含登录验证、角色验证、权限验证以及shiro登录注销流程(基于spring的方式,使用maven构建)

前言: shiro因为其简单.可靠.实现方便而成为现在最常用的安全框架,那么这篇文章除了会用简洁明了的方式讲一下基于spring的shiro详细配置和登录注销功能使用之外,也会根据惯例在文章最后总结一下shiro的大致配置使用流程,希望本篇文章能够后能给大家一种原来shiro这么简单的错觉感觉. 注意:该篇文章的开始是建立在一个完备的spring+mybatis的开发环境中,除了shiro之外的配置基本不会涉及到.做好自己--eguid原创文章 一.依赖的jar包 本篇文章使用shiro-1.4

从零开始实现asp.net MVC4框架网站的用户登录以及权限验证模块 详细教程

用户登录与权限验证是网站不可缺少的一部分功能,asp.net MVC4框架内置了用于实现该功能的类库,只需要简单搭建即可完成该功能. 下面详细介绍该功能的完成方法,尾部有实例源码下载,希望可以给刚开始接触MVC的朋友做个参考.     第一步:给VS安装MVC4框架 VS2012自带MVC4框架,其他版本可以使用独立安装包进行安装,这里就不讨论了,本例使用VS2013创建,.NET4.0+MVC4 第二步:创建MVC4网站项目         选择文件-新建-项目,按下图示例创建一个空的MVC网

Spring MVC + Shiro 实现权限验证

MAVEN的pom.xml 引入shiro(Spring MVC+mybatis 请参见上一章). <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.5</version> </dependency> <!-- http://mvnrepository.co

SpringMVC+Apache Shiro+JPA(hibernate)案例教学(二)基于SpringMVC+Shiro的用户登录权限验证

序: 在上一篇中,咱们已经对于项目已经做了基本的配置,这一篇文章开始学习Shiro如何对登录进行验证. 教学: 一.Shiro配置的简要说明. 有心人可能注意到了,在上一章的applicationContext.xml配置文件中,包含以下配置. <!-- 項目自定义的Realm --> <bean id="shiroDbRealm" class="org.shiro.demo.service.realm.ShiroDbRealm" ><

Spring整合Shiro做权限控制模块详细案例分析

1.引入Shiro的Maven依赖 <!-- Spring 整合Shiro需要的依赖 --> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.1</version> </dependency> <dependency> <groupId

Spring框架整合Struts2使用Validation框架验证表单用户输入数据的详细教程

原创整理不易,转载请注明出处:Spring框架整合Struts2使用Validation框架验证表单用户输入数据的详细教程 代码下载地址:http://www.zuidaima.com/share/1778685765291008.htm 在<Struts2教程4:使用validate方法验证数据>中曾讲到使用validate方法来验证客户端提交的数据,但如果使用validate方法就会将验证代码和正常的逻辑代码混在一起,但这样做并不利于代码维护,而且也很难将过些代码用于其他程序的验证.在St