Shiro简介以及与SSM整合

码云例子:https://gitee.com/luxins/shiroDemo1.git

1.简介

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

2.功能简介

• 基本功能点如下图所示:
在这里插入图片描述

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

3.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

4.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 提高了一些常见的加密组件用于如密码加密/解密。

与Web 集成

• Shiro 提供了与 Web 集成的支持,其通过一个
ShiroFilter 入口来拦截需要安全控制的URL,然后
进行相应的控制
• ShiroFilter 类似于如 Strut2/SpringMVC 这种
web 框架的前端控制器,是安全控制的入口点,其
负责读取配置(如ini 配置文件),然后判断URL
是否需要登录/权限等工作。
ShiroFilter:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
部分细节
• [urls] 部分的配置,其格式是: “url=拦截器[参数],拦截
器[参数]”;
• 如果当前请求的 url 匹配 [urls] 部分的某个 url 模式,将会
执行其配置的拦截器。
• anon(anonymous) 拦截器表示匿名访问(即不需要登
录即可访问)
• authc (authentication)拦截器表示需要身份认证通过后
才能访问

shiro的默认过滤器

在这里插入图片描述

URL 匹配模式

• url 模式使用 Ant 风格模式
• Ant 路径通配符支持 ?、*、**,注意通配符匹配不
包括目录分隔符“/”:
– ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不
匹配 /admin 或 /admin/;
– *:匹配零个或多个字符串,如 /admin 将匹配 /admin、
/admin123,但不匹配 /admin/1;
:匹配路径中的零个或多个路径,如 /admin/ 将匹
配 /admin/a 或 /admin/a/b

URL 匹配顺序

• URL 权限采取第一次匹配优先的 方式,即从头开始
使用第一个匹配的 url 模式对应的拦截器链。
• 如:
– /bb/=filter1
– /bb/aa=filter2
– /
=filter3
– 如果请求的url是“/bb/aa”,因为按照声明顺序进行匹
配,那么将使用 filter1 进行拦截。

认证/登录(先做整合后再测试)

为啥使用MD5盐值加密:
在doGetAuthenticationInfo的返回值创建SimpleAuthenticationInfo 对象的时候需要使用比较复杂的构造器  SimpleAuthenticationInfo Info=new SimpleAuthenticationInfo(username, credentials,salt,getName());盐值需要唯一:一般使用随机字符串或者userId;
使用 
  ByteSource salt=ByteSource.Util.bytes(username);//盐
Object simpleHash = new SimpleHash("MD5","123",salt,1024);进行计算加密后的值.



密码比对是通过AuthorizingRealm 的credentialsMatcher属性进行比对token中的和SimpleAuthenticationInfo 

1.获取当前subject对象
Subject subject= SecurityUtils.getSubject();
2.测试当前用户是否认证,即是否登录了,调用subject的isAuthenticated();
boolean authenticated = subject.isAuthenticated();
3.若当前没有认证,则把用户名密码封装为UsernamePasswordToken对象
1).创建一个表单页面
2).把请求提交到SpringMVC的handler
3)获取用户名密码
4.代用subject的login(AuthenticationToken token)方法执行登录
 @RequestMapping("/login")
    public String add(User u){

        Subject subject= SecurityUtils.getSubject();
        if(!subject.isAuthenticated()){
            UsernamePasswordToken usernamePasswordToken=new UsernamePasswordToken(u.getName(),u.getAge());
            usernamePasswordToken.setRememberMe(true);

            try {
                subject.login(usernamePasswordToken);
            }catch (UnknownAccountException e){
                System.out.println("没有该账户");
            }catch (IncorrectCredentialsException e){
                System.out.println("密码错误");
            }catch (LockedAccountException e){
                System.out.println("账户被锁定");
            }catch (Exception e){
                System.out.println("登录失败");
            }
        }
        return "index";

    }
5.自定义realm的方法,从数据库中获取相应的数据,返回给给shiro
1).extends AuthorizingRealm
2).实现方法 doGetAuthenticationInfo(AuthenticationToken authenticationToken)
6.由shiro进行密码比对

public class ShiroRealm extends AuthorizingRealm {

    @Override
    public String getName() {
        return super.getName();
    }

    //认证

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("-----------"+authenticationToken);
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        System.out.println("------->"+username);
        String s = token.getPassword().toString();
		//加盐
		

        if ("123".equals(username)){
            throw new UnknownAccountException("用户不存在");
        }if ("123456".equals(username)){
            throw new IncorrectCredentialsException("密码错误");
        }
//SimpleAuthenticationInfo 中传入的是数据库中查询的username和password
    SimpleAuthenticationInfo Info=new SimpleAuthenticationInfo(username, "64c8b1e43d8ba3115ab40bcea57f010b", getName());
//如果加盐
  String credentials="";
        if ("123".equals(username)){
            throw new UnknownAccountException("用户不存在");
        }if ("123456".equals(username)){
            throw new IncorrectCredentialsException("密码错误");
        }if ("admin".equals(username)){
             credentials="c41d7c66e1b8404545aa3a0ece2006ac";
        }
        

        //加盐
        ByteSource salt=ByteSource.Util.bytes(username);//盐
        //SimpleAuthenticationInfo中封装的是从数据库中查询的的username和password
         SimpleAuthenticationInfo Info=new SimpleAuthenticationInfo(username, credentials,salt,getName());
    


        return Info;
}
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
      /*
        * 1.继承AuthorizingRealm类,并且实现doGetAuthorizationInfo方法
        * 2.AuthorizingRealm继承类AuthenticatingRealm,但是没有实现AuthenticatingRealm中的doGetAuthorizationInfo
        * 方法,所以认证和授权只需要继承AuthorizingRealm,同时实现它的两个抽象方法.
        *
        * */
        /*
        * 1.从PrincipalCollection获取登录的信息
        * 2.从登录信息中获取当前用户的角色和权限(可能会查询数据库)
        * 3.创建SimpleAuthorizationInfo对象,并设置roles;
        * 4.返回SimpleAuthorizationInfo对象
        * */
        Object primaryPrincipal = principalCollection.getPrimaryPrincipal();

        Set<String> set=new HashSet<>();

        if ("user".equals(primaryPrincipal)){
            set.add("user");
        }
        if("admin".equals(primaryPrincipal)){
            set.add("admin");
        }
        SimpleAuthorizationInfo s=new SimpleAuthorizationInfo(set);
        return s;
    
    }
//MD5加密
//1.如何把字符串加密为md5
//2.替换realm的CredentialMatcher属性,直接使用HashCredentialMatcher对象,并设置加密方式即可.
将shiro配置文件的自己的realm的bean修改
 <bean id="jdbcRealm" class="com.lx.shiro.realms.ShiroRealm">
        <!--配置MD5加密-->
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
            //加密方式
                <property name="hashAlgorithmName" value="MD5"></property>
                //加密次数
                <property name="hashIterations" value="1024"></property>
            </bean>
        </property>
    </bean>
取得MD5加密后的字符串:null位置为盐;
    public static void main(String[] args) {
    //如果需要加盐
       //加盐
        ByteSource salt=ByteSource.Util.bytes(username);//盐
        Object simpleHash = new SimpleHash("MD5","123",null,1024);
        System.out.println(simpleHash);
    }


}

页面

<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" %>
<html>
<body>
<h2>Hello World!</h2>
<form action="/user/login" method="post">

    <input type="text" placeholder="name" name="name">
    <input type="text" placeholder="pass" name="age">
    <input type="submit" value="Login">
</form>
</body>
</html>

index.jsp
<%@page contentType="text/html; charset=utf-8" pageEncoding="UTF-8" %>
<%@taglib uri="http://shiro.apache.org/tags" prefix="shiro"%>
<html>
<body>
<h2>index html!</h2>

welcome:<shiro:principal>  </shiro:principal>

<shiro:hasRole name="admin">
    <a href="/admin.jsp">Admin.jsp</a>
</shiro:hasRole>
<shiro:hasRole name="user">

    <a href="/user.jsp">User.jsp</a>
</shiro:hasRole>


<a href="/user/logout">注 销</a>

</body>
</html>

unauthorized.jsp
<%@ page contentType="text/html;charset=utf-8"%>
<html>
<body>
<h2>没有权限</h2>
</body>
</html>
其他页面都是空白


身份验证

• 身份验证:一般需要提供如身份 ID 等一些标识信息来表明登录者的身
份,如提供 email,用户名/密码来证明。
• 在 shiro 中,用户需要提供 principals (身份)和 credentials(证
明)给 shiro,从而应用能验证用户身份:
• principals:身份,即主体的标识属性,可以是任何属性,如用户名、
邮箱等,唯一即可。一个主体可以有多个 principals,但只有一个
Primary principals,一般是用户名/邮箱/手机号。
• credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证
书等。
• 最常见的 principals 和 credentials 组合就是用户名/密码了

身份验证基本流程

• 1、收集用户身份/凭证,即如用户名/密码
• 2、调用 Subject.login 进行登录,如果失败将得到相应
的 AuthenticationException 异常,根据异常提示用户
错误信息;否则登录成功
• 3、创建自定义的 Realm 类,继承
org.apache.shiro.realm.AuthorizingRealm 类,实现
doGetAuthenticationInfo() 方法

身份验证示例

在这里插入图片描述

AuthenticationException

• 如果身份验证失败请捕获 AuthenticationException 或其子类
• 最好使用如“用户名/密码错误”而不是“用户名错误”/“密码错误”,
防止一些恶意用户非法扫描帐号库;
在这里插入图片描述

身份认证流程

• 1、首先调用 Subject.login(token) 进行登录,其会自动委托给
SecurityManager
• 2、SecurityManager 负责真正的身份验证逻辑;它会委托给
Authenticator 进行身份验证;
• 3、Authenticator 才是真正的身份验证者,Shiro API 中核心的身份
认证入口点,此处可以自定义插入自己的实现;
• 4、Authenticator 可能会委托给相应的 AuthenticationStrategy 进
行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用
AuthenticationStrategy 进行多 Realm 身份验证;
• 5、Authenticator 会把相应的 token 传入 Realm,从 Realm 获取
身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处
可以配置多个Realm,将按照相应的顺序及策略进行访问。

Realm

• Realm:Shiro 从 Realm 获取安全数据(如用户、角色、
权限),即 SecurityManager 要验证用户身份,那么它需
要从 Realm 获取相应的用户进行比较以确定用户身份是否
合法;也需要从Realm得到用户相应的角色/权限进行验证
用户是否能进行操作
• Realm接口如下
在这里插入图片描述
• 一般继承 AuthorizingRealm(授权)即可;其继承了
AuthenticatingRealm(即身份验证),而且也间接继承了
CachingRealm(带有缓存实现)。
• Realm 的继承关系:
在这里插入图片描述

Authenticator

• Authenticator 的职责是验证用户帐号,是 Shiro API 中身份验
证核心的入口点:如果验证成功,将返回AuthenticationInfo 验
证信息;此信息中包含了身份及凭证;如果验证失败将抛出相应
的 AuthenticationException 异常
• SecurityManager 接口继承了 Authenticator,另外还有一个
ModularRealmAuthenticator实现,其委托给多个Realm 进行
验证,验证规则通过 AuthenticationStrategy 接口指定

AuthenticationStrategy

• AuthenticationStrategy 接口的默认实现:
• FirstSuccessfulStrategy:只要有一个 Realm 验证成功即可,只返回第
一个 Realm 身份验证成功的认证信息,其他的忽略;
• AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和
FirstSuccessfulStrategy 不同,将返回所有Realm身份验证成功的认证信
息;
• AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有
Realm身份验证成功的认证信息,如果有一个失败就失败了。
• ModularRealmAuthenticator 默认是 AtLeastOneSuccessfulStrategy
策略

注销

配置shiro
在这里插入图片描述
Controller
在这里插入图片描述
页面
在这里插入图片描述

授权

• 授权,也叫访问控制,即在应用中控制谁访问哪些资源(如访问页面/编辑数据/页面操作
等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限
(Permission)、角色(Role)。
• 主体(Subject):访问应用的用户,在 Shiro 中使用 Subject 代表该用户。用户只有授权
后才允许访问相应的资源。
• 资源(Resource):在应用中用户可以访问的 URL,比如访问 JSP 页面、查看/编辑某些
数据、访问某个业务方法、打印文本等等都是资源。用户只要授权后才能访问。
• 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户
有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源,如:访问用
户列表页面查看/新增/修改/删除用户数据(即很多时候都是CRUD(增查改删)式权限控
制)等。权限代表了用户有没有操作某个资源的权利,即反映在某个资源上的操作允不允
许。
• Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,
即实例级别的)
• 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有
一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、CTO、开发工程师等
都是角色,不同的角色拥有一组不同的权限。

Shiro 支持三种方式的授权:

– 编程式:通过写if/else 授权代码块完成
– 注解式:通过在执行的Java方法上放置相应的注解完成,没有权限将抛出相
应的异常
– JSP/GSP 标签:在JSP/GSP 页面通过相应的标签完成
在这里插入图片描述

默认拦截器

• Shiro 内置了很多默认的拦截器,比如身份验证、授权等
相关的。默认拦截器可以参考
org.apache.shiro.web.filter.mgt.DefaultFilter中的枚举
拦截器:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Permissions

• 规则: 资源 标识符:操作:对象实例 例 ID 即对哪个资源的哪个
实例可以进行什么操作. 其 默认支持通配符权限字符串,: 表
示 资源/ / 操作/ / 实例的分割;, 表示 操作的 分割,* 表示 任意资
源/ / 操作/ / 实例。
• 多层次管理:
– 例如:user:query、user:edit
– 冒号 是一个特殊字符,它用来分隔权限字符串的下一 部件:第一部分
是权限被操作的领域(打印机),第二部分是被执行的操作。
– 多个值: 每个 部件能够保护多个值。因此,除了授予用户 user:query
和 user:edit 权限外,也 可以 简单地授予他们一 个: user: query , edit
– 还可以用 用 * 号 代替所有的值,如:user:* , 也可以写:*:query,表示
某个用户在所有的领域都有 query 的权限

Shiro 的 Permissions

• 实例 级访问控制
– 这种情况通常会使用三个部件: 域、操作、被付诸实
施的实例。如:user:edit:manager
– 也 可以使用通配符来定义,如:user:edit:、user::
user:
:manager
– 部分 省略 通配符:缺少的部件意味着用户可以访问所
有与之匹配的值,比如:user:edit 等价于 user:edit :
user 等价于 user:
?
– 注意: 通配符只能 从字符串的结尾处省略部件,也就
是说 user:edit 并不等价于 user:*:edit
授权流程

流程如下:

• 1、首先调用 Subject.isPermitted*/hasRole* 接口,其会委托给
SecurityManager,而 SecurityManager 接着会委托给 Authorizer;
• 2、Authorizer是真正的授权者,如果调用如
isPermitted(“user:view”),其首先会通过
• PermissionResolver 把字符串转换成相应的 Permission 实例;
• 3、在进行授权之前,其会调用相应的 Realm 获取 Subject 相应的角
色/权限用于匹配传入的角色/权限;
• 4、Authorizer 会判断 Realm 的角色/权限是否和传入的匹配,如果
有多个Realm,会委托给 ModularRealmAuthorizer 进行循环判断,
如果匹配如 isPermitted*/hasRole* 会返回true,否则返回false表示
授权失败。

ModularRealmAuthorizer

• ModularRealmAuthorizer 进行多 Realm 匹配流程:
– 1、首先检查相应的 Realm 是否实现了实现了Authorizer;
– 2、如果实现了 Authorizer,那么接着调用其相应的
isPermitted*/hasRole* 接口进行匹配;
– 3、如果有一个Realm匹配那么将返回 true,否则返回 false。

Shiro 标签

• Shiro 提供了 JSTL 标签用于在 JSP 页面进行权限控制,如
根据登录用户显示相应的页面按钮。
• guest 标签:用户没有身份验证时显示相应信息,即游客
访问信息:
在这里插入图片描述
• user 标签:用户已经经过认证/记住我登录后显示相应的信
息。
在这里插入图片描述
• authenticated 标签:用户已经身份验证通过,即
Subject.login登录成功,不是记住我登录的
在这里插入图片描述
• notAuthenticated 标签:用户未进行身份验证,即没有调
用Subject.login进行登录,包括记住我自动登录的也属于
未进行身份验证。
在这里插入图片描述
• pincipal 标签:显示用户身份信息,默认调用
Subject.getPrincipal() 获取,即 Primary Principal。
在这里插入图片描述
• hasRole 标签:如果当前 Subject 有角色将显示 body 体内
容:
在这里插入图片描述
• hasAnyRoles 标签:如果当前Subject有任意一个
角色(或的关系)将显示body体内容。
在这里插入图片描述
• lacksRole:如果当前 Subject 没有角色将显
示 body 体内容
在这里插入图片描述
• hasPermission:如果当前 Subject 有权限
将显示 body 体内容
在这里插入图片描述
• lacksPermission:如果当前Subject没有权
限将显示body体内容
在这里插入图片描述

权限注解

• @RequiresAuthentication:表示当前Subject已经通过login
进行了身份验证;即 Subject. isAuthenticated() 返回 true
• @RequiresUser:表示当前 Subject 已经身份验证或者通过记
住我登录的。
• @RequiresGuest:表示当前Subject没有身份验证或通过记住
我登录过,即是游客身份。
• @RequiresRoles(value={“admin”, “user”}, logical=
Logical.AND):表示当前 Subject 需要角色 admin 和user
• @RequiresPermissions (value={“user:a”, “user:b”},
logical= Logical.OR):表示当前 Subject 需要权限 user:a 或
user:b。

真实中进行授权

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/>
        <property name="successUrl" value="/list.jsp"/>
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>

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


        	<!--配置哪些页面需要受保护.-->
        	<!--以及访问这些页面需要的权限.-->
        	<!--1). anon 可以被匿名访问-->
        	<!--2). authc 必须认证(即登录)后才可能访问的页面.-->
        	<!--<!-3). logout 登出.&ndash;&gt;-->
        <!--4). roles 角色过滤器-->

不要配置:
        <!--<property name="filterChainDefinitions">-->
            <!--<value>-->
                <!--/login.jsp = anon-->
                <!--/user/login = anon-->
                <!--/user/logout = logout-->
                <!--/user.jsp = roles[user]-->
                <!--/admin.jsp =roles[admin]-->
                <!--# everything else requires authentication:-->
                <!--/** = authc-->
            <!--</value>-->
        <!--</property>-->

    </bean>
    <!-- 配置一个 bean, 该 bean 实际上是一个 Map. 通过实例工厂方法的方式 -->
    <bean id="filterChainDefinitionMap"
          factory-bean="filterChainDefinitionMapBuilder" factory-method="buiStringStringLinkedHashMap"></bean>

    <bean id="filterChainDefinitionMapBuilder"
          class="com.lx.utils.FilterChainDefinitionMapBuilder"></bean>

FilterChainDefinitionMapBuilder.java

package com.lx.utils;

import java.util.LinkedHashMap;
import java.util.LinkedList;

public class FilterChainDefinitionMapBuilder {

    public LinkedHashMap<String,String> buiStringStringLinkedHashMap(){
        LinkedHashMap<String,String> linkedHashMap=new LinkedHashMap<String,String>();

        linkedHashMap.put("/login.jsp","anon");
        linkedHashMap.put("/user/login","anon");
        linkedHashMap.put("/user.jsp","roles[user]");
        linkedHashMap.put("/admin.jsp","roles[admin]");

        linkedHashMap.put("/**","authc");

        return linkedHashMap;
    }
}

会话

概述
• Shiro 提供了完整的企业级会话管理功能,不依赖于底层容
器(如web容器tomcat),不管 JavaSE 还是 JavaEE 环境
都可以使用,提供了会话管理、会话事件监听、会话存储/
持久化、容器无关的集群、失效/过期支持、对Web 的透明
支持、SSO 单点登录的支持等特性

会话相关的 API

• Subject.getSession():即可获取会话;其等价于
Subject.getSession(true),即如果当前没有创建 Session 对象会创建
一个;Subject.getSession(false),如果当前没有创建 Session 则返回
null
• session.getId():获取当前会话的唯一标识
• session.getHost():获取当前Subject的主机地址
• session.getTimeout() & session.setTimeout(毫秒):获取/设置当
前Session的过期时间
• session.getStartTimestamp() & session.getLastAccessTime():
获取会话的启动时间及最后访问时间;如果是 JavaSE 应用需要自己定
期调用 session.touch() 去更新最后访问时间;如果是 Web 应用,每
次进入 ShiroFilter 都会自动调用 session.touch() 来更新最后访问时间
• session.touch() & session.stop():更新会话最后访问时
间及销毁会话;当Subject.logout()时会自动调用 stop 方法
来销毁会话。如果在web中,调用 HttpSession. invalidate()
也会自动调用Shiro Session.stop 方法进行销毁Shiro 的会

• session.setAttribute(key, val) &
session.getAttribute(key) &
session.removeAttribute(key):设置/获取/删除会话属
性;在整个会话范围内都可以对这些属性进行操作
• 会话监听器用于监听会话创建、过期及停止事件
在这里插入图片描述

缓存

CacheManagerAware 接口
• Shiro 内部相应的组件(DefaultSecurityManager)会自
动检测相应的对象(如Realm)是否实现了
CacheManagerAware 并自动注入相应的
CacheManager。
• Shiro 提供了 CachingRealm,其实现了
CacheManagerAware 接口,提供了缓存的一些基础实现;
• AuthenticatingRealm 及 AuthorizingRealm 也分别提
供了对AuthenticationInfo 和 AuthorizationInfo 信息的缓
存。
清除缓存

// 清除缓存
	public void clearCached() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		super.clearCache(principals);
	}

Session缓存

• 如 SecurityManager 实现了 SessionSecurityManager,
其会判断 SessionManager 是否实现了
CacheManagerAware 接口,如果实现了会把
CacheManager 设置给它。
• SessionManager 也会判断相应的 SessionDAO(如继承
自CachingSessionDAO)是否实现了
CacheManagerAware,如果实现了会把 CacheManager
设置给它
• 设置了缓存的 SessionManager,查询时会先查缓存,如
果找不到才查数据库。

5.集成SSM架构

0.0MAVEN依赖

 <properties>
    <junit.version>4.12</junit.version>
    <spring.version>4.3.8.RELEASE</spring.version>
    <mybatis.version>3.4.5</mybatis.version>
    <mybatis.spring.version>1.3.0</mybatis.spring.version>
    <mapper.version>2.3.4</mapper.version>
    <mysql.version>5.1.38</mysql.version>
    <slf4j.version>1.6.4</slf4j.version>
    <jackson.version>2.9.7</jackson.version>
    <c3p0.version>0.9.5-pre10</c3p0.version>
    <jstl.version>1.2</jstl.version>
    <servlet-api.version>3.1.0</servlet-api.version>
    <jsp-api.version>2.2.1</jsp-api.version>
    <commons-lang3.version>3.3.2</commons-lang3.version>
    <commons-io.version>1.3.2</commons-io.version>
  </properties>

  <dependencies>

    <!-- 单元测试 -->
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>${junit.version}</version>
      <scope>test</scope>
    </dependency>

    <!-- Spring -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-beans</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-webmvc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>${spring.version}</version>
    </dependency>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>${spring.version}</version>
    </dependency>

    <!-- Mybatis -->
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis</artifactId>
      <version>${mybatis.version}</version>
    </dependency>
    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>${mybatis.spring.version}</version>
    </dependency>

    <!-- 通用Mapper -->
    <dependency>
      <groupId>com.github.abel533</groupId>
      <artifactId>mapper</artifactId>
      <version>${mapper.version}</version>
    </dependency>

    <!-- MySql -->
    <dependency>
      <groupId>mysql</groupId>
      <artifactId>mysql-connector-java</artifactId>
      <version>${mysql.version}</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>${slf4j.version}</version>
    </dependency>

    <!-- Jackson Json处理工具包 -->
    <dependency>
      <groupId>com.fasterxml.jackson.core</groupId>
      <artifactId>jackson-databind</artifactId>
      <version>${jackson.version}</version>
    </dependency>

    <!-- c3p0数据源 -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>${c3p0.version}</version>
    </dependency>

    <!-- JSP相关 -->
    <dependency>
      <groupId>jstl</groupId>
      <artifactId>jstl</artifactId>
      <version>${jstl.version}</version>
    </dependency>

    <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>javax.servlet-api</artifactId>
      <version>${servlet-api.version}</version>
      <scope>provided</scope>
    </dependency>

    <dependency>
      <groupId>javax.servlet.jsp</groupId>
      <artifactId>javax.servlet.jsp-api</artifactId>
      <version>${jsp-api.version}</version>
      <scope>provided</scope>
    </dependency>


    <!-- Shrio框架依赖 -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.2.3</version>
    </dependency>

    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
    </dependency>
    <!-- Shrio框架依赖 -->

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-log4j12</artifactId>
      <version>1.7.12</version>
    </dependency>
  </dependencies>

1.配置SSM

配置applicationContext.xml

<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context" xmlns:p="http://www.springframework.org/schema/p"
	   xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
	   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
	http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
	http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
	http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd">

	<!--使用spring自带的占位符替换功能 -->
	<bean
			class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<!-- 忽略没有找到的资源文件 -->
		<property name="ignoreResourceNotFound" value="true" />
		<!-- 配置资源文件 -->
		<property name="locations">
			<list>
				<value>classpath:db.properties</value>
			</list>
		</property>
	</bean>

	<!--1.扫描包 -->
	<context:component-scan base-package="com.lx" />

	<!--2. 配置数据源 c3p0 -->
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
		  destroy-method="close">
		<property name="driverClass" value="${jdbc.driverClassName}" />
		<property name="jdbcUrl" value="${jdbc.url}" />
		<property name="user" value="${jdbc.username}" />
		<property name="password" value="${jdbc.password}" />
		<!-- 请求超时时间 -->
		<property name="checkoutTimeout" value="30000" />
		<!-- 每60秒检查所有连接池中的空闲连接。默认值: 0,不检查 -->
		<property name="idleConnectionTestPeriod" value="30" />
		<!-- 连接数据库连接池最大空闲时间 -->
		<property name="maxIdleTime" value="30" />
		<!-- 连接池初始化连接数 -->
		<property name="initialPoolSize" value="5" />
		<property name="minPoolSize" value="5" />
		<property name="maxPoolSize" value="20" />
		<!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。默认值: 3 -->
		<property name="acquireIncrement" value="5" />
	</bean>

	<!--3.定义SqlSessionFactory -->
	<bean class="org.mybatis.spring.SqlSessionFactoryBean">
		<property name="configLocation" value="classpath:mybatis-config.xml" />
		<property name="dataSource" ref="dataSource" />
		<!-- 自动扫描mapping.xml文件 -->
		<property name="mapperLocations" value="classpath:mappers/*.xml"></property>
		<property name="typeAliasesPackage" value="com.lx.bean" />
	</bean>

	<!--4.定义Mapper接口的扫描器 -->
	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<property name="basePackage" value="com.lx.mapper" />
	</bean>

	<!--5.定义事务管理器 -->
	<bean id="transactionManager"
		  class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource" />
	</bean>

	<!-- 6.开启事务注解支持 -->
	<tx:annotation-driven transaction-manager="transactionManager" />

</beans>

2.配置SpringMVC.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:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p" xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/mvc
        http://www.springframework.org/schema/mvc/spring-mvc.xsd">

    <!-- 扫表包:控制层包 -->
    <context:component-scan base-package="com.lx.controller" />

    <!-- 视图解析器 -->
    <bean
            class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <!-- jsp所在的位置 -->
        <property name="prefix" value="/" />
        <!-- 文件后缀 -->
        <property name="suffix" value=".jsp"></property>
    </bean>
    <!-- 全部资源放行 -->
    <mvc:annotation-driven/>
    <!-- 对指定目录下的静态资源放行 -->
    <mvc:resources location="statics/images/" mapping="/images/**"/>
    <mvc:resources location="statics/css/" mapping="/css/**"/>
    <mvc:resources location="statics/js/" mapping="/js/**"/>

    <mvc:default-servlet-handler/>
</beans>

3.mybatis-config.xml

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

</configuration>

4.db.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/ssm?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root

5.log4j.properties

log4j.rootLogger=INFO,Console,File  
#定义日志输出目的地为控制台
log4j.appender.Console=org.apache.log4j.ConsoleAppender  
log4j.appender.Console.Target=System.out  
#可以灵活地指定日志输出格式,下面一行是指定具体的格式
log4j.appender.Console.layout = org.apache.log4j.PatternLayout  
log4j.appender.Console.layout.ConversionPattern=[%c] - %m%n  

#文件大小到达指定尺寸的时候产生一个新的文件
log4j.appender.File = org.apache.log4j.RollingFileAppender  
#指定输出目录
log4j.appender.File.File = logs/ssm.log  
#定义文件最大大小
log4j.appender.File.MaxFileSize = 10MB  
# 输出所以日志,如果换成DEBUG表示输出DEBUG以上级别日志
log4j.appender.File.Threshold = ALL  
log4j.appender.File.layout = org.apache.log4j.PatternLayout  
log4j.appender.File.layout.ConversionPattern =[%p] [%d{yyyy-MM-dd HH\:mm\:ss}][%c]%m%n

6.userMapper.xml

<?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.wb.mapper.LoginlogMapper">

    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.wb.bean.Loginlog">
        <id column="id" property="id" />
        <result column="ip" property="ip" />
        <result column="no" property="no" />
        <result column="createtime" property="createtime" />
        <result column="location" property="location" />
    </resultMap>
    <!-- 通用查询结果列 -->
    <sql id="Base_Column_List">
        id, ip, no, createtime, location
    </sql>
</mapper>

7.配web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/javaee"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         id="WebApp_ID" version="2.5">
  <!--spring的配置-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext*.xml</param-value>
  </context-param>

  <!-- 添加Spring的上下文环境监听 -->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>


  <!-- 配置SpringMvc核心的控制器 DispatcherServlet -->
  <servlet>
    <servlet-name>DispatcherServlet</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <!-- 配置DispatcherServlet的初始化參數:设置文件的路径和文件名称 -->
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>classpath:spring-mvc.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>DispatcherServlet</servlet-name>
    <!--不能写/*,必须写/,这是REST URL风格的要求,REST风格会在后面介绍 -->
    <url-pattern>/</url-pattern>
  </servlet-mapping>

  <!-- 解决工程编码过滤器 -->
  <filter>
    <filter-name>characterEncodingFilter</filter-name>
    <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
    <init-param>
      <param-name>encoding</param-name>
      <param-value>UTF-8</param-value>
    </init-param>
    <init-param>
      <param-name>forceEncoding</param-name>
      <param-value>true</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>characterEncodingFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
</web-app>

8.集成shiro

1.引入maven依赖
 <!-- Shrio框架依赖 -->
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-core</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-web</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-spring</artifactId>
      <version>1.2.3</version>
    </dependency>
    <dependency>
      <groupId>org.apache.shiro</groupId>
      <artifactId>shiro-ehcache</artifactId>
      <version>1.2.3</version>
    </dependency>

    <dependency>
      <groupId>commons-logging</groupId>
      <artifactId>commons-logging</artifactId>
      <version>1.1.3</version>
    </dependency>
    <!-- Shrio框架依赖 -->
  </dependencies>
2.在web.xml中配置shiroFilter
<!--
	1. 配置  Shiro 的 shiroFilter.
	2. DelegatingFilterProxy 实际上是 Filter 的一个代理对象. 默认情况下, Spring 会到 IOC 容器中查找和
	<filter-name> 对应的 filter bean. 也可以通过 targetBeanName 的初始化参数来配置 filter bean 的 id.
	-->
  <filter>
    <filter-name>shiroFilter</filter-name>
    <!-- shiro过虑器,DelegatingFilterProxy通过代理模式将spring容器中的bean和filter关联起来 -->
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    <!-- 设置true由servlet容器控制filter的生命周期 -->
    <init-param>
      <param-name>targetFilterLifecycle</param-name>
      <param-value>true</param-value>
    </init-param>
    <!-- 设置spring容器filter的bean id,如果不设置则找与filter-name一致的bean -->
    <init-param>
      <param-name>targetBeanName</param-name>
      <param-value>shiroFilter</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>


3.配置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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <!--
     1. 配置 SecurityManager!
     -->
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
        <property name="cacheManager" ref="cacheManager"/>
        <property name="sessionMode" value="native"/>
        <property name="realm" ref="jdbcRealm"/>
   </bean>
    <!--
  2. 配置 CacheManager.
  2.1 需要加入 ehcache 的 jar 包及配置文件.
  -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
             <!--<property name="cacheManager" ref="ehCacheManager"/> -->
        <property name="cacheManagerConfigFile" value="classpath:ehcache.xml"/>
    </bean>
    <bean id="authenticator"
          class="org.apache.shiro.authc.pam.ModularRealmAuthenticator">
        <property name="authenticationStrategy">
            <bean class="org.apache.shiro.authc.pam.AtLeastOneSuccessfulStrategy"></bean>
        </property>
    </bean>
    <!--
      3. 配置 Realm
      3.1 直接配置实现了 org.apache.shiro.realm.Realm 接口的 bean
  -->
    <bean id="jdbcRealm" class="com.lx.shiro.realms.ShiroRealm"></bean>
    <!--
   4. 配置 LifecycleBeanPostProcessor. 可以自定的来调用配置在 Spring IOC 容器中 shiro bean 的生命周期方法.
   -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- Enable Shiro Annotations for Spring-configured beans.  Only run after
         the lifecycleBeanProcessor has run: -->
    <!--
    5. 启用 IOC 容器中使用 shiro 的注解. 但必须在配置了 LifecycleBeanPostProcessor 之后才可以使用.
    -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
          depends-on="lifecycleBeanPostProcessor"/>
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
    <!--
   6. 配置 ShiroFilter.
   6.1 id 必须和 web.xml 文件中配置的 DelegatingFilterProxy 的 <filter-name> 一致.
                     若不一致, 则会抛出: NoSuchBeanDefinitionException. 因为 Shiro 会来 IOC 容器中查找和 <filter-name> 名字对应的 filter bean.
   -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
        <property name="securityManager" ref="securityManager"/>
        <property name="loginUrl" value="/login.jsp"/>
        <property name="successUrl" value="/list.jsp"/>
        <property name="unauthorizedUrl" value="/unauthorized.jsp"/>

        <!--<property name="filterChainDefinitionMap" ref="filterChainDefinitionMap"></property>-->
        	<!--配置哪些页面需要受保护.-->
        	<!--以及访问这些页面需要的权限.-->
        	<!--1). anon 可以被匿名访问-->
        	<!--2). authc 必须认证(即登录)后才可能访问的页面.-->
        	<!--<!-3). logout 登出.&ndash;&gt;-->
        <!--4). roles 角色过滤器-->


        <property name="filterChainDefinitions">
            <value>
                /login.jsp = anon
                /shiro/login = anon
                /shiro/logout = logout
                /user.jsp = roles[user]
                /admin.jsp = roles[admin]
                # everything else requires authentication:
                /** = authc
            </value>
        </property>
    </bean>
</beans>

	<!-- 5.会话管理器 -->
	<bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
		<!-- session的失效时长,单位毫秒   1000ms=1m-->
		<property name="globalSessionTimeout" value="10000" />
		<!-- 删除失效的session -->
		<property name="deleteInvalidSessions" value="true" />
	</bean>
自定义Realm
package com.lx.shiro.realms;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @author luxin
 * @create 2019-05-29 17:09
 */
public class ShiroRealm extends AuthorizingRealm {

    @Override
    public String getName() {
        return super.getName();
    }
    //认证(登录)
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        return null;
    }
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }
// 清除缓存
	public void clearCached() {
		PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
		super.clearCache(principals);
	}




}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值