Java---Shiro框架

news2024/11/16 1:33:07

第一章   入门概述

1.1 什么是shiro

        Apache Shiro 是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完成:认证、授权、加密、会话管理、与 Web 集成、缓存 等。借助 Shiro 您可以快速轻地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。

  • 下载地址

    • 官网:Apache Shiro | Simple. Java. Security.
    • github:GitHub - apache/shiro: Apache Shiro

 1.2 为什么要用shiro

        自 2003 年以来,框架格局发生了相当大的变化,因此今天仍然有很多系统在使用Shiro。这与 Shiro 的特性密不可分。

        易于使用:使用 Shiro 构建系统安全框架非常简单。就算第一次接触也可以快速掌握。

        全面:Shiro 包含系统安全框架需要的功能,满足安全需求的“一站式服务”。

        灵活:Shiro 可以在任何应用程序环境中工作。虽然它可以在 Web、EJB 和 IOC 环境中工作,但不需要依赖它们。Shiro 也没有强制要求任何规范,甚至没有很多依赖项。

        强力支持 Web:Shiro 具有出色的 Web 应用程序支持,可以基于应用程序 URL 和Web 协议(例如 REST)创建灵活的安全策略,同时还提供一组 JSP 库来控制页面输出。

        兼容性强:Shiro 的设计模式使其易于与其他框架和应用程序集成。Shiro 与Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin 等框架无缝集成。

1.3 Shiro 与 SpringSecurity 的对比

1、Spring Security 基于 Spring 开发,项目若使用 Spring 作为基础,配合 SpringSecurity 做权限更加方便,而 Shiro 需要和 Spring 进行整合开发;

2、Spring Security 功能比 Shiro 更加丰富些,例如安全维护方面;

3、Spring Security 社区资源相对比 Shiro 更加丰富;

4、Shiro 的配置和使用比较简单,Spring Security 上手复杂些;

5、Shiro 依赖性低,不需要任何框架和容器,可以独立运行Spring Security 依赖Spring 容器;

6、shiro 不仅仅可以使用在 web 中,它可以工作在任何应用环境中。在集群会话时 Shiro最重要的一个好处或许就是它的会话是独立于容器的。

1.4 有哪些功能?


(1)Authentication:身份认证/登录,验证用户是不是拥有相应的身份。

(2)Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能进行什么操作,如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限。

(3)Session Management:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境,也可以是Web 环境的。

(4)Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储。

(5)Web Support:Web 支持,可以非常容易的集成到Web 环境。

(6)Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率。

(7)Concurrency:Shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去。

(8)Testing:提供测试支持。

(9)“Run As”:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问。

(10)Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。

1.5 Shiro架构(外部)

image-20200729114702566

从外部来看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。

1.6  Shiro架构(内部)

image-20200729114720578

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

第二章 shiro登录认证

1. 创建数据库
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0 ;
-- ----------------------------
-- Table structure for user
-- ----------------------------
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`uid` int ( 11 ) NOT NULL AUTO_INCREMENT,
`uname` varchar ( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`pwd` varchar ( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL ,
`sex` varchar ( 2 ) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL ,
`address` varchar ( 200 ) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT
NULL ,
`state` int ( 2 ) DEFAULT NULL ,
`salt` varchar ( 32 ) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL ,
PRIMARY KEY (`uid`) USING BTREE,
UNIQUE INDEX `uname`(`uname`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 4 CHARACTER SET = utf8 COLLATE =
utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of user
-- ----------------------------
INSERT INTO `user` VALUES ( 1 , 'admin' , '727d8b2b4c59366d7ace58d4eda4cfee' , ' ' ,
' 河南洛阳 ' , 1 , '9C2AB20283F9450389330033D64686DD' );
INSERT INTO `user` VALUES ( 2 , 'zs' , '83f12ba7c4357b87167e240a22c15248' , ' ' , '
南郑州 ' , 1 , '262F995823C94D1CAE7596B47E8AB657' );
select * from user
2. 创建 web 项目并配置 SSM
完成 user 表的 dao 层和 service 层的书写
3. 创建 MyShiroRealm 继承 AuthorizingRealm
注意:使用 @Component 注解交给 spring 管理
package com.chen.shiro;
import com.chen.bean.User;
import com.chen.service.IUserService;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
4.在spring.xml中配置shiro管理器和自定义的Realm
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* token 里面是客户端发来的信息(包含输入的用户名 和 密码)
* 自定义Realm,通过mybatis查询数据库的密码和盐值,让shiro进行身份验证
*/
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
IUserService userService;
//shiro 进行授权操作
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principals) {
return null;
}
//shiro 进行认证操作
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken
token) throws AuthenticationException {
//token 是主体传过来的身份令牌
//1 获取用户身份信息
String uname = token.getPrincipal().toString();
//2 调用业务层获取用户信息(数据库中)
User user = userService.findByUname(uname);
//3 判断并将数据完成封装
if(user!=null){
AuthenticationInfo authenticationInfo=new SimpleAuthenticationInfo(
token.getPrincipal(), //令牌身份信息对象
user.getPwd(), //用户数据库的密码
ByteSource.Util.bytes(user.getSalt().getBytes()), //加密时的
盐值
uname // 用户名
);
return authenticationInfo;
}
return null;
}
}

 4.spring.xml中配置shiro管理器和自定义的Realm

<!--=================shiro相关配置====================-->
<!--配置shiro进行校验时的加密规则-->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--加密规则-->
<property name="hashAlgorithmName" value="MD5" />
<!--是否加盐-->
<property name="hashSalted" value="true" />
<!--是否增加哈希算法进行散列-->
<!-- <property name="hashIterations" value="1024" />-->
</bean>
<!--配置自定义Realm-->
<bean id="myRealm" class="com.chen.shiro.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!--配置安全管理器,使用自定义的Realm-->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--配置自定义的Realm-->
<property name="realm" ref="myRealm" />
</bean>
<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 调用我们配置的权限管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 配置拦截后我们的登录请求地址 -->
<property name="loginUrl" value="/loginUI"/>
<!-- 如果您请求的资源不再您的权限范围,则跳转到错误页面 -->
<property name="unauthorizedUrl" value="/error"/>
<!-- 权限配置
anon:任何人都可以访问; authc:必须是登录之后才能进行访问,不包括remember
me;
perms:指定过滤规则,可以自己拓展权限配置; roles:配置角色;
user:登录用户才可以访问,包含remember me; logout:退出
-->
<property name="filterChainDefinitions">
<value>
/=anon
/index = anon
/loginUI = anon
/login = anon
/WEB-INF/view/login.html = anon
/**/*.js=anon
/**/*.css=anon
/**=authc
/**=user
</value>
</property>
</bean>
权限配置
anon :任何人都可以访问;
authc :必须是登录之后才能进行访问,不包括 remember me
perms :指定过滤规则,可以自己拓展权限配置;
roles :配置角色;
user :登录用户才可以访问,包含 remember me
logout :退出

5.web.xml中配置shiro的过滤器

<!-- shiro配置 -->
<filter>
<filter-name>shiroFilter</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filterclass>
<init-param>
<param-name>targetFilterLifecycle</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

 6.controller中进行shiro认证

package com.chen.controller;

import com.chen.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
public class UserController {
    @Autowired
    UserService userService;

    @RequestMapping("/login")
    public String login(String uname, String pwd, HttpSession session) {
        System.out.println(uname+"------------------");
        //1 获取 Subject 对象
        Subject subject = SecurityUtils.getSubject();
//2 封装请求数据到 token 对象中
        AuthenticationToken token = new UsernamePasswordToken(uname, pwd);
//3 调用 login 方法进行登录认证
        try {
            //5.验证主体是否能够登录
            subject.login(token);
            session.setAttribute("user", token.getPrincipal().toString());
            return "main";
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在!");
            return "login";
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误!");
            return "login";
        } catch (AuthenticationException e) {
            System.out.println("认证失败,不知道出了什么问题");
            return "login";
        }
    }
}

第三章 shirorememberMe功能

Shiro 提供了记住我( RememberMe )的功能,比如访问一些网站时,关闭了浏览器, 下次再打 开时还是能记住你是谁, 下次访问时无需再登录即可访问。
例如:当没有登录时,访问 /main 主页,会被拦截跳转到登录页面。当登录后是可以正常访
/main 的主页的;如果使用了记住我功能,会在浏览器写入 cookie ,关掉浏览器不需要登录即可 直接访问/main
基本流程
1. 首先在登录页面选中 RememberMe 然后登录成功;如果是浏览器登录,一般会 把
RememberMe Cookie 写到客户端并保存下来;
2. 关闭浏览器再重新打开;会发现浏览器还是记住你的;
3. 访问一般的网页服务器端,仍然知道你是谁,且能正常访问;
4. 但是,如果我们访问电商平台时,如果要查看我的订单或进行支付时,此时还 是需要再进行身份认
证的,以确保当前用户还是你。
1. spring.xml 中配置 cookie 的设置和 rememberMe 理器

1.配置记住我功能的cookie设置;

2. 配置记住我功能的管理器;
3. 在安全管理器中引用记住我功能的管理器;
4. 在过滤器中 shiroFilter 配置 rememberMe 的过滤配置( /**=user
<!--=================shiro相关配置====================-->
<!--配置shiro进行校验时的加密规则-->
<bean id="credentialsMatcher"
class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
<!--加密规则-->
<property name="hashAlgorithmName" value="MD5" />
<!--是否加盐-->
<property name="hashSalted" value="true" />
<!--是否增加哈希算法进行散列-->
<!-- <property name="hashIterations" value="1024" />-->
</bean>
<!--配置自定义Realm-->
<bean id="myRealm" class="com.chen.shiro.MyRealm">
<property name="credentialsMatcher" ref="credentialsMatcher" />
</bean>
<!--=================记住我功能相关配置====================-->
<!--记住我功能的cookie设置-->
<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!--设置cookie的属性名-->
<property name="name" value="rememberMe" />
<!--设置cookie存在根目录,可在同一应用服务器内共享-->
<property name="path" value="/" />
<!--通过JavaScript脚本将无法读取到Cookie信息,这样能有效的防止XSS攻击,让网站应用更
加安全-->
<property name="httpOnly" value="true" />
<!--设置cookie的失效时间为30天-->
<property name="maxAge" value="2592000" />
</bean>
<!--记住我功能的管理器配置-->
<bean id="rememberMeManager"
class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<!--引用cookie设置-->
<property name="cookie" ref="simpleCookie" />
<!--默认AES算法,设置cookie的加密算法,采用的是base64的加密-->
<property name="cipherKey" value="#
{T(org.apache.shiro.codec.Base64).decode('4AvVhmFLUs0KTA3Kprsdag==')}" />
</bean>
<!--配置安全管理器,使用自定义的Realm-->
<bean id="securityManager"
class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<!--配置自定义的Realm-->
<property name="realm" ref="myRealm" />
<!--====引用rememberMe功能管理器====================-->
<property name="rememberMeManager" ref="rememberMeManager" />
</bean>
<!-- 配置shiro的过滤器工厂类,id- shiroFilter要和我们在web.xml中配置的过滤器一致 -->
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<!-- 调用我们配置的权限管理器 -->
<property name="securityManager" ref="securityManager"/>
<!-- 配置拦截后我们的登录请求地址 -->
<property name="loginUrl" value="/loginUI"/>
<!-- 如果您请求的资源不再您的权限范围,则跳转到错误页面 -->
<property name="unauthorizedUrl" value="/error"/>
<!-- 权限配置 -->
<!-- 权限配置
anon:任何人都可以访问; authc:必须是登录之后才能进行访问,不包括remember
me;
perms:指定过滤规则,可以自己拓展权限配置; roles:配置角色;
user:登录用户才可以访问,包含remember me; logout:退出
-->
<property name="filterChainDefinitions">
<value>
/=anon
/index = anon
/loginUI = anon
/login = anon
/WEB-INF/view/login.html = anon
/**/*.js=anon
/**/*.css=anon
/**=authc
/**=user
</value>
</property>
</bean>
2. 页面上添加记住我勾选的复选框按钮,并设置 name 属性 rememberMe
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
<body>
<div id="content">
    <form class="form-horizontal" action="/login" method="post">
        <div class="form-group">
            <label for="uname" class="col-sm-2 control-label">帐号</label>
            <div class="col-sm-10">
                <input type="text" name="uname" class="form-control" id="uname"
                       placeholder="帐号">
            </div>
        </div>
        <div class="form-group">
            <label for="pwd" class="col-sm-2 control-label">密码</label>
            <div class="col-sm-10">
                <input type="password" name="pwd" class="form-control" id="pwd"
                       placeholder="密码">
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <div class="checkbox">
                    <label>
                        <input type="checkbox" name="rerememberMe"> 记住我
                    </label>
                </div>
            </div>
        </div>
        <div class="form-group">
            <div class="col-sm-offset-2 col-sm-10">
                <button type="submit" id="login" class="btn btn-primary">登录
                </button>
                <a href="/indexUI">去注册</a>
            </div>
        </div>
    </form>
</div>
</body>
</html>
3. 修改 controller ,或者记住我功能是否勾选,认证时添加 记住我标记
1. 配置 boolean 类型的请求参数 rerememberMe ,并设置默认值是 false
2. 在封装 token 时,加入 rerememberMe 标记;

package com.chen.controller;

import com.chen.service.UserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.authz.annotation.RequiresRoles;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpSession;

@Controller
public class UserController {
    @Autowired
    UserService userService;

    @RequestMapping("/login")
    public String login(String uname, String pwd, @RequestParam(defaultValue = "false") boolean rerememberMe, HttpSession session) {
        System.out.println(uname+"------------------");
        //1 获取 Subject 对象
        Subject subject = SecurityUtils.getSubject();
//2 封装请求数据到 token 对象中
        AuthenticationToken token = new UsernamePasswordToken(uname, pwd,rerememberMe);
//3 调用 login 方法进行登录认证
        try {
            //5.验证主体是否能够登录
            subject.login(token);
            session.setAttribute("user", token.getPrincipal().toString());
            return "main";
        } catch (UnknownAccountException e) {
            System.out.println("用户名不存在!");
            return "login";
        } catch (IncorrectCredentialsException e) {
            System.out.println("密码错误!");
            return "login";
        } catch (AuthenticationException e) {
            System.out.println("认证失败,不知道出了什么问题");
            return "login";
        }
    }
}
4. 测试 rerememberMe 功能
1. 不登录直接访问主页 /main shiro 会拦截去到登录页;登录后可以正常访问主页 /main
2. 登录时不勾选记住我,关闭浏览器访问主页 /main 还会拦截到登录页;
3. 登录时勾选记住我,关闭浏览器访问主页 /main 可以正常访问;

第四章 shiro的登出

1.在主页设置退出登录的链接

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>主页</title>
<body>
<img src="/img/index.jpg">
<a href="/logout">退出登录</a>
</body>
</html>
2. spring.xml 配置文件中找到 shiro 过滤器,配置登出的 操作
<property name="filterChainDefinitions">
<value>
/=anon
/index = anon
/loginUI = anon
/login = anon
/logout=logout
/WEB-INF/view/login.html = anon
/**/*.js=anon
/**/*.css=anon
/**=authc
/**=user
</value>
</property>

第六章 shiro角色授权认证

1. 在主页设计两个超链接,分别模拟查看用户管理和系统管
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页</title>
</head>
<body>
<h2>内容页</h2>
<a href="/loginOut">退出登录</a>
<hr>
<ul>
    <li><a href="/user">用户管理</a></li>
    <li><a href="/system">系统管理</a></li>
</ul>
</body>
</html>
2. 在控制器中使用 @RequiresRoles("roles") 注解来开启请 求的角色验证
   @RequiresRoles("user")
    @RequestMapping("/user")
    public String user(){
        System.out.println("用户管理");
        return "userList";
    }
    @RequiresRoles("admin")
    @RequestMapping("/system")
    public String system(){
        System.out.println("系统管理");
        return "system";
    }
3. springmvc.xml 中开启 shiro 的注解支持
由于 shiro 注解是在 controller 中配置,所以需要在 springmvc.xml 中配置 shiro 的注解支持;
1. 配置 shiro bean 生命周期处理器
2. 配置自动创建代理;
3. 开启 shiro 注解的支持

    <!--配置shiro bean生命周期处理器-->
    <bean id="lifecycleBeanPostProcessor"
          class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>
    <!--配置自动创建代理-->
    <bean
            class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <!-- 开启shiro注解的支持 -->
    <bean
            class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager" />
    </bean>
4. 在主页访问两个超链接出现异常,提示操作没有对应的角
报错信息如下:
org.springframework.web.util.NestedServletException: Request processing
failed; nested exception is org.apache.shiro.authz.UnauthorizedException:
Subject does not have role [admin]
5. 模拟进行角色认证,在自定义的 Realm 类的授权方法中, 手动给用户添加角色(后期使用数据库查询是否有角色), 然后查看能否正常访问。
@Component
public class MyRealm extends AuthorizingRealm {
@Autowired
UserService userService;
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection
principalCollection) {
System.out.println("授权方法被执行==============");
//创建角色和权限对象
SimpleAuthorizationInfo authorizationInfo=new SimpleAuthorizationInfo();
//模拟添加角色
authorizationInfo.addRole("user");
//返回权限
return authorizationInfo;
}
...

第七章 shiro权限授权认证

1. 在用户管理设计用户增删改查操作,分别模拟权限验证
<body>
<ul>
<li><a href="/user/add">添加用户</a></li>
<li><a href="/user/delete">删除用户</a></li>
<li><a href="/user/find">查看用户</a></li>
<li><a href="/user/revise">修改用户</a></li>
</ul>
</body>
2.shiro 配置参考如上
3. 在控制器中使用 @RequiresPermissions("permission") 注解来开启请求 的角色验证

    @RequiresPermissions("user:add")
    @RequestMapping("/user/add")
    @ResponseBody
    public String add(){
        System.out.println("用户添加操作");
        return "action user add...";
    }
    @RequiresPermissions("user:add")
    @RequestMapping("/user/delete")
    @ResponseBody
    public String delete(){
        System.out.println("用户删除操作");
        return "action user delete...";
    }
    @RequiresPermissions("user:find")
    @RequestMapping("/user/find")
    @ResponseBody
    public String find(){
        System.out.println("用户查看操作");
        return "action user find...";
    }
    @RequiresPermissions("user:revise")
    @RequestMapping("/user/revise")
    @ResponseBody
    public String revise(){
        System.out.println("用户修改操作");
        return "action user revise...";
    }
4. 在自定义的 Realm 类的授权方法中,手动给用户添加权限 (后期使用数据库查询是否有权限),然后查看能否正常访 问。
package com.chen.shior;

import com.chen.bean.User;
import com.chen.service.UserService;
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 org.springframework.stereotype.Component;

/**
 * 自定义Realm,通过mybatis查询教据库密码和盐值,让shiro进行身份验证
 */
@Component
public class MyShiroRealm extends AuthorizingRealm {
    @Autowired
    UserService userService;

    //shiro 进行授权操作
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权方法被执行==============");
        //1.创建角色和权限对象
        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

        //2.1 获取用户登录
        String uname = principalCollection.getPrimaryPrincipal().toString();
        System.out.println("当前登录用户为:"+uname);
        if (uname.equals("admin")){
            //正常查询用户的角色(数据库使用set) 现在模拟赋予角色
            String role ="admin";
            authorizationInfo.addRole(role);
            authorizationInfo.addRole("user");

            //授予权限正常查询用户的权限,现在模拟赋予权限
            authorizationInfo.addStringPermission("user:add");
            authorizationInfo.addStringPermission("user:delete");
            authorizationInfo.addStringPermission("user:find");
            authorizationInfo.addStringPermission("user:revise");
            }else {
            authorizationInfo.addRole("user");
            authorizationInfo.addStringPermission("user:add");
            authorizationInfo.addStringPermission("user:find");
        }
        //返回权限
        return authorizationInfo;
    }

}
.......
5. 测试看能否访问用户管理页面
配置了 add 权限,点击用户添加可以正常访问;
点击用户删除则抛出异常如下:
org.springframework.web.util.NestedServletException: Request processing
failed; nested exception is org.apache.shiro.authz.UnauthorizedException:
Subject does not have permission [user:delete]

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/815073.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

释放三年版本:Aspose.Total For NET [21.7/22.7/23.7]

请各位对号入座&#xff0c;选择自己需求范围&#xff0c;你懂的&#xff0c;你懂的&#xff0c;你懂的 Aspose.Total for .NET is the most complete package of all .NET File Format Automation APIs offered by Aspose. It empowers developers to create, edit, render, …

日撸java_day54-55

文章目录 第 54 、55 天: 基于 M-distance 的推荐代码运行截图 第 54 、55 天: 基于 M-distance 的推荐 1.M-distance, 就是根据平均分来计算两个用户 (或项目) 之间的距离. 2.邻居不用 k 控制. 距离小于 radius (即 ϵ ) 的都是邻居. 使用 M-distance 时, 这种方式效果更好. …

tinkerCAD案例:28. Build a Mobile Amplifier 构建移动放大器(3)

tinkerCAD案例&#xff1a;28. Build a Mobile Amplifier 构建移动放大器(3) 原文 step 1 “爵士乐”放大器 Lesson Overview: 课程概述&#xff1a; Now we’re going to decorate our design! 现在我们要装饰我们的设计&#xff01; step 2 In this step we will ref…

纯CSS实现手风琴效果(常用样式)

【效果图】&#xff1a; 【html代码】&#xff1a; <div class"rowd"><ul class"fold_wrap"><li><a href"#"><div class"pic_auto pic_auto1 trans"></div><div class"adv_intro flex&…

qt子进程和父进程读写数据通信

进程A&#xff08;例如主程序&#xff09;创建了一个QProcess B&#xff0c;这个B就称为A的子进程&#xff0c;而A称为B的父进程。 这也称为进程间通信&#xff0c;有多种方式&#xff1a; TCP/IPLocal Server/Socket共享内存D-Bus &#xff08;Unix库&#xff09;QProcess会…

Java版本企业电子招投标采购系统源码+功能模块功能描述+数字化采购管理 采购招投标

功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外部…

Android复习(Android基础-四大组件)—— Activity

Activity作为四大组件之首&#xff0c;是使用最为频繁的一种组件&#xff0c;中文直接翻译为"活动"&#xff0c;不过如果被翻译为"界面"会更好理解。正常情况&#xff0c;除了Window&#xff0c;Dialog和Toast &#xff0c; 我们能见到的界面只有Activity。…

【phaser微信抖音小游戏开发003】游戏状态state场景规划

经过目录优化后的执行结果&#xff1a; 经历过上001&#xff0c;002的规划&#xff0c;我们虽然实现了helloworld .但略显有些繁杂&#xff0c;我们将做以下的修改。修改后的目录和文件结构如图。 game.js//小游戏的重要文件&#xff0c;从这个开始。 main.js 游戏的初始化&a…

集合框架、多线程、IO流

目录 集合框架 Java迭代器&#xff08;Iterator&#xff09; Java集合类 Collection派生 Map接口派生&#xff1a; Java集合List ArrayList Vector LinkedList Java集合Set HashSet LinkedHashSet TreeSet Java集合Queue&#xff08;队列&#xff09; PriorityQue…

AP5101 高压线性恒流电源驱动 输入 24-36V 输出3串18V LED线性恒流驱动方案

1,输入 24V-36V 输出3串18V 直亮 参考BOM 表如下 2,输入 24V-36V 输出3串18V 直亮 参考线路图 如下​ 3&#xff0c;产品描述 AP5101B 是一款高压线性 LED 恒流芯片&#xff0c;外围简单、内置功率管&#xff0c;适用于6- 60V 输入的高精度降压 LED 恒流驱动芯片。最大…

cloudstack之advanced network

cloudstack网络模式的介绍&#xff0c;可参考【cloudstack之basic network】 一、添加资源 访问UI&#xff0c;默认端口为8080&#xff0c;默认用户民和密码是admin/password。点击【continue with installation】。修改默认密码选择zone type&#xff1a;core 选择advanced模…

python中的单引号、双引号和多引号

目录 python中的单引号 python中的双引号 python中的多引号 三者分别在什么时候使用&#xff0c;有什么区别 总结 python中的单引号 在Python中&#xff0c;单引号&#xff08;&#xff09;可以用来表示字符串。 可以使用单引号创建一个简单的字符串&#xff0c;例如&…

cad文件删除了怎么找回来?这7种方法帮你找回

用户咨询&#xff1a;我存在D盘的文件在今天中午突然不见了&#xff1f;全都是些CAD图纸&#xff0c;不知道是不是被我误删了&#xff0c;怎么才能找到这些图纸&#xff0c;对我很重要呢&#xff01;&#xff01;&#xff01; ——CAD文件删除了怎么找回来&#xff1f;误删除了…

测试平台——项目工程创建和配置

这里写目录标题 一、配置开发环境二、配置MySql数据库三、配置工程日志 一、配置开发环境 项目的环境分为开发环境和生产环境。 开发环境:用于编写和调试项目代码。 生产环境:用于项目线上部署运行。 base.py 修改BASE_DIR&#xff1a;拼接.parent 原因&#xff1a;原BASE_D…

数据包在网络中传输的过程

ref: 【先把这个视频看完了】&#xff1a;数据包的传输过程【网络常识10】_哔哩哔哩_bilibili 常识都看看 》Ref&#xff1a; 1. 这个写的嘎嘎好&#xff0c;解释了为啥4层7层5层&#xff0c;还有数据包封装的问题:数据包在网络中的传输过程详解_数据包传输_张孟浩_jay的博客…

ALLEGRO之File

本文主要讨论ALLEGRO软件中的File菜单。 &#xff08;1&#xff09;New&#xff1a;新建&#xff0c;用于新建Board/Package symbol等&#xff1b; &#xff08;2&#xff09;Open&#xff1a;打开&#xff0c;用于打开brd、dra等文件&#xff1b; &#xff08;3&#xff09;S…

C语言题目总结--操作符运用

&#x1f636;‍&#x1f32b;️Take your time ! &#x1f636;‍&#x1f32b;️ &#x1f4a5;个人主页&#xff1a;&#x1f525;&#x1f525;&#x1f525;大魔王&#x1f525;&#x1f525;&#x1f525; &#x1f4a5;代码仓库&#xff1a;&#x1f525;&#x1f525;魔…

【RabbitMQ(day3)】扇形交换机和主题交换机的应用

文章目录 第三种模型&#xff08;Publish/Subscribe 发布/订阅&#xff09;扇型&#xff08;funout&#xff09;交换机Public/Subscribe 模型绑定 第四、第五种模型&#xff08;Routing、Topics&#xff09;第四种模型&#xff08;Routing&#xff09;主题交换机&#xff08;To…

京东LBS推荐算法实践

1、推荐LBS业务介绍 1.1 业务场景 现有的同城购业务围绕京东即时零售能力搭建了到店、到家两种业务场景。同城业务与现有业务进行互补&#xff0c;利用高频&#xff0c;时效性快的特点&#xff0c;可以有效提升主站复访复购频次&#xff0c;是零售的重要战略方向。 1.2 名词…

运行vue项目显示找不到vue-cli

直接下载ruoyi源码到本地&#xff0c;启动ruoyi-ui的时候报错&#xff1a; 原来是电脑没配置nodejs。 所以先去官网下载nodejs&#xff0c;然后安装完之后&#xff0c;在命令行窗口输入&#xff1a; 显示安装成功。 但还没有结束&#xff0c;还要配置npm的全局模块的存放路径…