shiro框架详解

shiro认证和授权

啥叫权限?
程序里面的权限是啥?

就是访问路径,路径在程序中对应的就是某种能能力和资源。

如何控制权限显示呢?

权限不应该属于某一个实体,而是属于某一个角色,只不过这个是题拥有了这个角色,而拥有了

这个权限

就是RBAC权限管理思想,不是直接将权限交给用户,而是给用户分配角色,角色赋予用户相应的权限

这样大大地减少了系统的开销

基于RBAC思想进行权限的控制显示
2.搭建web项目(ssm+layUI+freemarker)

RBAC思想:基于角色的权限的控制

什么是权限:就是访问一个资源和操作的某个资源的资格,权限

代码中的权限:一个具体的资源路径

项目中添加权限管理:

  1. 不同的账号有不同的权限显示
  2. 访问之前要验证,当前账号是否有权限

基于RBAC思想

五张表:

用户表

​ 用户角色表

角色表

​ 角色权限表

权限表

三个表之间多对多关系

一、认证和授权的含义

一个完整的权限控制应该包含两个流程

  1. 认证(Authentication):就是检查账号和密码的过程。
  2. 授权(Authorization):当前账号是否包含相应的角色和权限的过程。
注意 :

授权发生在认证之后,因为授权需要认证的通过

认证:Authentication

授权:Authorrization

二、shiro框架介绍

1. 啥是shiro

是一个基于RBAC思想的权限管理框架

Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication,
authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can
quickly and easily secure any application – from the smallest mobile applications to the largest web
and enterprise applications.

2.shiro能做什么

帮助我们进行认证、授权、密码管理和会话管理

3.shiro组成部分

用户-----》账号和密码------》shiro内部验证(

1.用户提供的账号和密码需要验证

2.查找正确的信息

3.进行验证)

三部分:

  1. 获取用户信息:subject
  2. 验证功能SecurityManager(认证(Authenticator)、授权(authorizer)、密码(cryptography)、会话(sessionManager))
  3. 获取正确的信息功能realm

两个获取一个验证

4.shiro执行流程

subject获取用户输入-------》SecurityManager拿subject和realm获取到的数据验证用户的输入信息的正确性《-----realm获真实的用户

三、shiro认证

就是验证账号和密码

使用
1. simpleAccountRealm
第一步导入依赖
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.4.1</version>
</dependency>
//获取用户名和密码账号和密码
     Scanner scanner = new Scanner(System.in);
     System.out.println("请输入账号");
     String account = scanner.nextLine();
     System.out.println("请输入密码");
     String password = scanner.nextLine();

     /**
         * todo 1:创建一个realm
         * SimpleAccountRealm
      */
     SimpleAccountRealm simpleAccountRealm = new SimpleAccountRealm();
     simpleAccountRealm.addAccount("root", "111");
     simpleAccountRealm.addAccount("admin", "222");
     
     /**
         * todo 2:创建securityManager并传入realm
         * 传入manager
      */
     DefaultSecurityManager securityManager = new DefaultSecurityManager(simpleAccountRealm);
     securityManager.setRealm(simpleAccountRealm);
     SecurityUtils.setSecurityManager(securityManager);


     /**
      *todo 3: 获取subject
      *TODO 并获取密码令牌传入用户和密码
      */
     Subject subject = SecurityUtils.getSubject();
     UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(account,password);
     
     /**
         * todo 验证 
      */
     try {
         subject.login(usernamePasswordToken);
         System.out.println("验证成功");
     } catch (AuthenticationException e) {
         e.printStackTrace();
         System.out.println("验证失败");
     }
simpleAccountRealm的优缺点
优点:

几乎没有优点

缺点:
  1. 只能输入账号和密码,以及角色,无法授权
  2. 一次缓存所有账号信息
2. iniRealm:

IniRealm就是就是存.ini 配置文件中加载进来用户账号和密码,角色权限的信息用来对账户进行认证和授权

方案一

配置文件

[main]
#securityManager=org.apache.shiro.mgt.DefaultSecurityManager
#securityManager = new DefaultSecurityManager();
#想在配置文件中初始化jdbcrealm 初始化连接池!以及修改jdbcrealm默认sql
macther=org.apache.shiro.authc.credential.HashedCredentialsMatcher
macther.hashAlgorithmName=md5
macther.hashIterations=108
md5realm=com.itqf.md5.Md5Realm
md5realm.credentialsMatcher=$macther
securityManager.realm=$md5realm
dataSource=com.mchange.v2.c3p0.ComboPooledDataSource
dataSource.jdbcUrl=jdbc:mysql:///shirotest
dataSource.driverClass=com.mysql.jdbc.Driver
dataSource.user=root
dataSource.password=root
jdbcRealm=org.apache.shiro.realm.jdbc.JdbcRealm
jdbcRealm.authenticationQuery=select lundanzi from user where ergouzi = ?
jdbcRealm.dataSource=$dataSource
securityManager.realm=$jdbcRealm
[users]
root=123
admin=111
 //创建Realm
            IniRealm iniRealm = new IniRealm("classpath:my.ini");
            DefaultSecurityManager securityManager = new DefaultSecurityManager();
            securityManager.setRealm(iniRealm);
            SecurityUtils.setSecurityManager(securityManager);

方案二:

//创建Realm
            IniSecurityManagerFactory iniSecurityManagerFactory = new 																			IniSecurityManagerFactory("classpath:my.ini");
            SecurityManager securityManager = iniSecurityManagerFactory.getInstance();
			SecurityUtils.setSecurityManager(securityManager);
  1. jdbcRealm

数据来源是数据库,账号密码以及权限角色

优点:

自动中查找账号信息,符合开发场景

缺点:

sql语句固定,也就是说表和字段名字固定—表明必须要叫users

里面要有password 和 username

  1. 自定义realm

数据可以来自任意位置

创建类继承

一、继承AuthorizingRealm

他可以用来认证账户和授权账户

 @Autowired
    private UserService userService;
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        User user = (User) principals.getPrimaryPrincipal();
        Set<String> roles =  userService.selectRolesByUsername(user.getUsername());
        System.out.println("roles = " + roles);
        Set<String> permissions = userService.selectPermisssionRoles(roles);
        System.out.println("permissions = " + permissions);
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.setRoles(roles);
        simpleAuthorizationInfo.setStringPermissions(permissions);

        return simpleAuthorizationInfo;
    }

//方法二
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        //第一步获取用户输入帐号
        String username = (String) token.getPrincipal();

        //第二部根据用户名查找用户
        User user = userService.selectUserByUsername(username);
        if (user == null) {
            //账号不存在
            return null;
        }else {
            SimpleAuthenticationInfo simpleAuthenticationInfo =
                    new SimpleAuthenticationInfo(user,user.getPassword(),"myrealm");
            return simpleAuthenticationInfo;//返回查询到的数据
        }
    }

二、继承AuthenticatingRealm

他只能对用户进行认证

它里面只有方法二,对用户进行认证

  1. 输入的账号

  2. 根据账号查询数据

  3. 根据产寻得数据判断,返回数据

    return null 账号不存在 不为空返回密码 数据对象

  4. 总结subject

subject获取用户数据

认证login()

之后subject 获取的是realm返回的数据

subject.getPrincipal();获取自定义realm嘻哈寻到的真实登陆的账号

subject.isAuthenticated();是否认证

subject.login() 认证

四、shiro授权

授权:就是认证后的账号进行角色和权限的验证

授权一定发生在认证的后边

1、角色授权
  1. subject.hasRole()|hasAllRoles|hasRoles返回true或者false 如果true就直接放行,否则跳转到

对应的提示页面

  1. subject.checkRole|checkedRoles()

没有角色就直接抛异常,进行补获,也面条装就行

2、权限授权

​ 授权只有check方法没有has方法

subject.checkPermiision()|checkPermissions()捕获异常,跳转页面

五、shiro的密码加密和加密处理

密码加密处理也是认证的一部分

认证就是账号密码认证的过程

MD5 sha1 内容摘要

能将字符串转化为另一种字符串,过程不可以逆转!

1. shiro提供的的数据操作工具类
1. Base64编码解码

可以将一个字符串或者字节数装华为一个更短的字符串,同样支持翻转

好处:1.存储的数据不是明文 类似加密的手段
2.数据更短!

String s = Base64.encodeToString(str.getBytes(“UTF-8”));
System.out.println("s = " + s);
String s1 = Base64.decodeToString(s.getBytes(“UTf-8”));

2. MD5、sha1工具类

new Md5Hash(需要转码的字符串, 盐,反复加盐的次数)

new Sha1Hash(转码的字符串, 盐, 反复加盐的次数)

六、shiro 整合商品展示的crud

商品展示

商品添加

权限

一般用户商品展示

管理员有添加功能

商品展示和商品添加都需要登陆

登陆页面任何人都可以直接访问

数据库表

用户表

​ 中间表

角色表

​ 中间表

权限表

商品表

技术:rbac\ssm\layui\freemarker\web\mysql

升级版:shiro

实现步骤:

  1. 数据库
  2. 项目搭建()
  3. ssm整合

七、shiro手动权限验证

手动验证和失败后的处理

需要我们在controller中进行代码判断+spring mvc异常处理!

八、shiro注解的使用

注解形式权限验证优点:

不干扰正常的代码的情况下添加权限管理,而且支持角色权限的or

注意注解里面的方法全部使用的是check,也就是如果正常就可以正常访问,否则抛异常

使用步骤:

步骤一:

在springmvc的配置文件中开启shiro的注解形式

<!-- 使用shiro注解 -->
<aop:aspectj-autoproxy proxy-target-class="true" />
	<!-- 注解使用声明好的securitymanager-->
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
		<property name="securityManager" ref="securityManager" />
	</bean>
步骤二 控制权限

@RequiresAuthentication : 表示当前Subject已经通过login 进行了身份验证;即 Subject. isAuthenticated() 返回 true (了解) authc
@RequiresUser : 表示当前 Subject 已经身份验证或者通过记住我登录的.(了解) user
@RequiresGuest : 表示当前Subject没有身份验证或通过记住我登录过,即是游客身份.(了解) anon
@RequiresRoles : 表示当前 Subject 需要角色. roles
@RequiresPermissions : 表示当前 Subject 需要权限. perms

九、过滤器

如何实现的?

过滤器优点:可以在访问之前进行权限控制,几乎不影响征程的业务逻辑

使用:

1:web.xml 文件中申明一个代理过滤器,代理过滤器帮助我们进行其他过滤器的初始化
 <filter>
	<filter-name>shiroFilter</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<async-supported>true</async-supported>
		<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>
2:可以申明对应饿的过滤器连

语法:路径=过滤器[],过滤器

<!-- 创建shiroFilter工厂实例 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 设置安全管理器 -->
    <property name="securityManager" ref="securityManager" />
    <!-- 设置登录页面 -->
    <property name="loginUrl" value="/login.jsp" />
    <!-- 设置没有权限后跳转的页面 -->
    <property name="unauthorizedUrl" value="403.jsp" />
    <!-- 登录成功后跳转的页面 -->
    <property name="successUrl" value="success.jsp" />
    <!-- 设置过滤器链 -->
    <property name="filterChainDefinitions">
        <value>
            <!-- 从上向下依次匹配 -->
            /login.jsp = anon
            /user/login = anon
            /logout = logout
            <!-- 配置权限过滤器 -->
            /user/roleTest1 = roles[超级管理员,人事]
            /user/permTest1 = perms[product:delete,product:insert]
            /* = authc
        </value>
    </property>
</bean>
3:常见的过滤器

认证相关

authc:认证---------subject.isAuthenticated()

anon

logout

user

授权相关的

roles

perms

十、自定义shiro过滤器

public class OrRolesFilter extends AuthorizationFilter {
public OrRolesFilter() {
}

@Override
protected boolean isAccessAllowed(ServletRequest request, 
                                  ServletResponse response, 
                                  Object mappedValue) throws Exception {
    // 获得主体.
    Subject subject = this.getSubject(request, response);
    // 获取配置文件中的数组.
    String[] rolesArray = (String[])((String[])mappedValue);
    // 如果数组不为null,并且长度不为0
    if (rolesArray != null && rolesArray.length != 0) {
        // 将数组转换为set集合
        Set<String> roles = CollectionUtils.asSet(rolesArray);
        // 手动判断!!!唯一修改的位置!!!
        for (String role : roles) {
            if(subject.hasRole(role)){
                return true;
            }
        }
        // 如果一个都不匹配再返回false,拦截.
        return false;
    } else {
        // 数组没值,直接方式.
        return true;
    }
}
配置自定义配置
<!-- 创建自定义过滤器 -->
<bean id="orRoles" class="com.qf.filter.OrRolesFilter" />

<!-- 创建shiroFilter工厂实例 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <!-- 设置安全管理器 -->
    <property name="securityManager" ref="securityManager" />
    <!-- 设置登录页面 -->
    <property name="loginUrl" value="/login.jsp" />
    <!-- 设置没有权限后跳转的页面 -->
    <property name="unauthorizedUrl" value="403.jsp" />
    <!-- 登录成功后跳转的页面 -->
    <property name="successUrl" value="success.jsp" />
    <!-- 添加自定义过滤器 -->
    <property name="filters">
        <map>
            <entry key="orRoles" value-ref="orRoles"></entry>
        </map>
    </property>
    <!-- 设置过滤器链 -->
    <property name="filterChainDefinitions">
        <value>
            <!-- 从上向下依次匹配 -->
            /login.jsp = anon
            /user/login = anon
            /logout = logout
            <!-- 配置权限过滤器 -->
            /user/roleTest1 = roles[超级管理员,人事]
            /user/permTest1 = perms[product:delete,product:insert]
            <!-- 使用自定义过滤器 -->
            /user/roleTest2 = orRoles[超人,人事]
            /* = authc
        </value>
    </property>
</bean>

十一、jsp使用shiro权限标签

不同角色或权限显示不同的页面内容

jsp中引入shiro标签
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    1. 用户名: <shiro:principal /><br />

    <shiro:user>2. 用户认证过,或者记住我了.</shiro:user><br />

    <shiro:authenticated>3. 用户认证过了就显示我.</shiro:authenticated><br />

    <shiro:guest>4. 没认证过,就显示我.</shiro:guest><br />

    <shiro:hasRole name="人事">5. 有人事角色就显示我.</shiro:hasRole><br />

    <shiro:hasAnyRoles name="超级管理员,超人">6. 有超级管理员或超人角色就显示我.</shiro:hasAnyRoles><br />

    <shiro:hasPermission name="product:delete">7. 有product:delete资源权限显示我.</shiro:hasPermission><br />

    <shiro:notAuthenticated>8. 没认证过显示我.</shiro:notAuthenticated><br />

    <shiro:lacksRole name="超人" >9. 没有超人角色显示我.</shiro:lacksRole><br />

    <shiro:lacksPermission name="user:delete" >10. 没有user:delete资源权限显示我.</shiro:lacksPermission><br />
</body>
</html>

十二、freemarker使用shiro权限标签

导入依赖:
		<dependency>
			<groupId>net.mingsoft</groupId>
			<artifactId>shiro-freemarker-tags</artifactId>
			<version>0.1</version>
		</dependency>
2.修改原有的页面静态化的配置类
public class MyFreemarkerConfigurer extends FreeMarkerConfigurer {
    @Override
    public void afterPropertiesSet() throws IOException, TemplateException {
        super.afterPropertiesSet();  //支持默认标签

        Configuration configuration = this.getConfiguration();

        //告诉页面静态化支持shiro标签
        configuration.setSharedVariable("shiro", new ShiroTags());

    }
}
配置spring mvc的页面静态化工具
<bean id="configruration"
              class="com.itqf.configurer.MyFreemarkerConfigurer">
            <!-- 模板放置的位置  / classpath resources-->
            <property name="templateLoaderPath" value="/WEB-INF/ftl/" />
            <property name="defaultEncoding" value="UTF-8" />
</bean>
3.ftl文件中使用shiro的标签
<@shiro.guest>游客登录</@shiro.guest>

            <@shiro.authenticated>

            <@shiro.principal property="username"/>

            </@shiro.authenticated>

            <@shiro.notAuthenticated>
		        当前身份未认证(包括记住我登录的)
		    </@shiro.notAuthenticated>
 
		    <@shiro.hasRole name="用户">
		        用户[<@shiro.principal/>]用户<br/>
		    </@shiro.hasRole>

		    <@shiro.hasAnyRoles name="用户,管理员,member">
		        用户[<@shiro.principal/>]拥有角色用户,管理员<br/>
		    </@shiro.hasAnyRoles>

  
		    <@shiro.lacksRole name="admin">
		        用户[<@shiro.principal/>]不拥有admin角色
		    </@shiro.lacksRole>


		    <@shiro.hasPermission name="user/add">
		        用户[<@shiro.principal/>]拥有user/add权限
		    </@shiro.hasPermission>


		    <@shiro.lacksPermission name="user/add">
		        用户[<@shiro.principal/>]不拥有user/add权限
		    </@shiro.lacksPermission>


		    <@shiro.user>
		    记住我/认证显示

十三、记住我

1.设置shiro配置文件添加cookie的设置
2.login之前需要设置rememberme状态

UsernamePasswordToken usernamePasswordToken =
new UsernamePasswordToken(user.getUsername(),user.getPassword());
//记住我
//记住我功能开启!如果认证通过,将返回的账号信息存到cookie recookie
usernamePasswordToken.setRememberMe(true);

3.user和authc

user是记住我状态
authc是认证!

注意:

要求记住我存储的数据对象全部需要实现序列化接口!否则会出现 deletemecookie!

十四、会话管理

suject.login() 默认是30分钟!

设置认证有效时间:

1.web.xml session-config timeout 单位分钟

2.shiro设计的方法

		            <!-- 单位是毫秒 超时时间-->
		            <property name="globalSessionTimeout" value="10000"></property>
		            <!-- 过期session是否删除-->
		            <property name="deleteInvalidSessions" value="true"></property>
		        </bean>



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值