Apache Shiro安全(权限框架)学习笔记

简介:

Apache Shiro 是 Java 的一个安全(权限)框架。
• Shiro 可以非常容易的开发出足够好的应用,其不仅可以用在
JavaSE 环境,也可以用在 JavaEE 环境。
• Shiro 可以完成:认证、授权、加密、会话管理、与Web 集成、缓存
等。
• 下载:http://shiro.apache.org/

基本功能:

Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用
户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户
对某个资源是否具有某个权限;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有
信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
• Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web 支持,可以非常容易的集成到Web 环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可
以提高效率;
Concurrency:Shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能
• 把权限自动传播过去;
Testing:提供测试支持;• Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登
录了

Shiro 架构 (Shiro外部来看)

• 从外部来看Shiro ,即从应用程序角度的来观察如何使用 Shiro 完成
工作:

Subject:应用代码直接交互的对象是 Subject,也就是说 Shiro 的对外
API 核心就是 Subject。Subject 代表了当前“用户”, 这个用户不一定
是一个具体的人,与当前应用交互的任何东西都是 Subject,如网络爬虫,
机器人等;与 Subject 的所有交互都会委托给 SecurityManager;
Subject 其实是一个门面,SecurityManager 才是实际的执行者;
SecurityManager:安全管理器;即所有与安全有关的操作都会与
SecurityManager 交互;且其管理着所有 Subject;可以看出它是 Shiro
的核心,它负责与 Shiro 的其他组件进行交互,它相当于 SpringMVC 中
DispatcherServlet 的角色
Realm:Shiro 从 Realm 获取安全数据(如用户、角色、权限),就是说
SecurityManager 要验证用户身份,那么它需要从 Realm 获取相应的用户
进行比较以确定用户身份是否合法;也需要从 Realm 得到用户相应的角色/
权限进行验证用户是否能进行操作;可以把 Realm 看成 DataSource

Shiro架构(Shiro内部来看)

Subject:任何可以与应用交互的“用户”;
SecurityManager :相当于SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏;
所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进
行认证、授权、会话及缓存的管理。
Authenticator:负责 Subject 认证,是一个扩展点,可以自定义实现;可以使用认证
策略(Authentication Strategy),即什么情况下算用户认证通过了;
Authorizer:授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控
制着用户能访问应用中的哪些功能;
Realm:可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体
的;可以是JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要
实现自己的 Realm;
SessionManager:管理 Session 生命周期的组件;而 Shiro 并不仅仅可以用在 Web
环境,也可以用在如普通的 JavaSE 环境
CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据
基本上很少改变,放到缓存中后可以提高访问的性能
Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密/解密。

 HelloWorld应用

加入如下 jar 包:
– shiro-all-1.3.2.jar
– log4j-1.2.15.jar
– slf4j-api-1.6.1.jar
– slf4j-log4j12-1.6.1.jar

package com.mikey.www;

/**
 * @author Mikey
 * @Title:
 * @Description:
 * @date 2018/11/1 21:32
 * @Version 1.0
 */
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


/**
 * Simple Quickstart application showing how to use Shiro's API.
 *
 * @since 0.9 RC2
 */
public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {

        // The easiest way to create a Shiro SecurityManager with configured
        // realms, users, roles and permissions is to use the simple INI config.
        // We'll do that by using a factory that can ingest a .ini file and
        // return a SecurityManager instance:

        // Use the shiro.ini file at the root of the classpath
        // (file: and url: prefixes load from files and urls respectively):
        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();

        // for this simple example quickstart, make the SecurityManager
        // accessible as a JVM singleton.  Most applications wouldn't do this
        // and instead rely on their container configuration or web.xml for
        // webapps.  That is outside the scope of this simple quickstart, so
        // we'll just do the bare minimum so you can continue to get a feel
        // for things.
        SecurityUtils.setSecurityManager(securityManager);

        // Now that a simple Shiro environment is set up, let's see what you can do:

        // get the currently executing user:
        // 获取当前的 Subject. 调用 SecurityUtils.getSubject();
        Subject currentUser = SecurityUtils.getSubject();

        // Do some stuff with a Session (no need for a web or EJB container!!!)
        // 测试使用 Session
        // 获取 Session: Subject#getSession()
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("---> Retrieved the correct value! [" + value + "]");
        }

        // let's login the current user so we can check against roles and permissions:
        // 测试当前的用户是否已经被认证. 即是否已经登录.
        // 调动 Subject 的 isAuthenticated()
        if (!currentUser.isAuthenticated()) {
            // 把用户名和密码封装为 UsernamePasswordToken 对象
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            // rememberme
            token.setRememberMe(true);
            try {
                // 执行登录.
                currentUser.login(token);
            }
            // 若没有指定的账户, 则 shiro 将会抛出 UnknownAccountException 异常.
            catch (UnknownAccountException uae) {
                log.info("----> There is no user with username of " + token.getPrincipal());
                return;
            }
            // 若账户存在, 但密码不匹配, 则 shiro 会抛出 IncorrectCredentialsException 异常。
            catch (IncorrectCredentialsException ice) {
                log.info("----> Password for account " + token.getPrincipal() + " was incorrect!");
                return;
            }
            // 用户被锁定的异常 LockedAccountException
            catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            // 所有认证时异常的父类.
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //say who they are:
        //print their identifying principal (in this case, a username):
        log.info("----> User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        // 测试是否有某一个角色. 调用 Subject 的 hasRole 方法.
        if (currentUser.hasRole("schwartz")) {
            log.info("----> May the Schwartz be with you!");
        } else {
            log.info("----> Hello, mere mortal.");
            return;
        }

        //test a typed permission (not instance-level)
        // 测试用户是否具备某一个行为. 调用 Subject 的 isPermitted() 方法。
        if (currentUser.isPermitted("lightsaber:weild")) {
            log.info("----> You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        // 测试用户是否具备某一个行为.
        if (currentUser.isPermitted("user:delete:zhangsan")) {
            log.info("----> You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //all done - log out!
        // 执行登出. 调用 Subject 的 Logout() 方法.
        System.out.println("---->" + currentUser.isAuthenticated());

        currentUser.logout();

        System.out.println("---->" + currentUser.isAuthenticated());

        System.exit(0);
    }
}
Quickstart

 日常报错:

1.Tomcat报错:部署项目失败:Unknown version string [4.0]. Default version will be used.

Connected to server
[2018-11-01 10:26:13,142] Artifact Shiro_Spring_Web:war exploded: Artifact is being deployed, please wait...
十一月 01, 2018 10:26:13 下午 org.apache.catalina.deploy.WebXml setVersion
警告: Unknown version string [4.0]. Default version will be used.
十一月 01, 2018 10:26:13 下午 org.apache.catalina.startup.TldConfig execute
信息: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
十一月 01, 2018 10:26:13 下午 org.apache.catalina.core.StandardContext startInternal
严重: One or more listeners failed to start. Full details will be found in the appropriate container log file
十一月 01, 2018 10:26:13 下午 org.apache.catalina.core.StandardContext startInternal
严重: Context [] startup failed due to previous errors
[2018-11-01 10:26:13,545] Artifact Shiro_Spring_Web:war exploded: Error during artifact deployment. See server log for details.
报错信息

报错原因:

解决方法:

重新配置run as 的Tomcat

参考博客:https://blog.csdn.net/qq_32483145/article/details/80292463

猜你喜欢

转载自www.cnblogs.com/biaogejiushibiao/p/9896586.html