shiro:整合springboot快速上手(附带代码示例)(1)

简介: shiro:整合springboot快速上手(附带代码示例)(1)

shiro

阿帕奇的安全框架


Apache Shiro是一个java的安全管理框架,可以用在javaEE环境下,也可以用在javaSE环境下。


此前我们学习了很多有关阿帕奇的东西:maven,tomcat,等等


官方号称十分钟就可以入门,


官网:https://shiro.apache.org/


为什么学他?:


(1)spring security 功能完善,学习成本偏高;

(2)shiro 学习成本低,简单的安全框架,基本功能存在(登录认证,权限认证); 

(3)spring mvc interceptor(拦截器) 只能做登录认证,不能做权限认证。


他能做什么?

1.png

2.png

Authentication:身份认证/登录;


Authorization:授权;


Session Manager:会话管理;


Cryptography:加密;


Web Support:**Web支持,可以非常容易的集成到Web环境;


Caching:缓存;


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


Testing:提供测试支持;


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


Remember Me:记住我。


Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro。


shiro架构

Subject:主体;


SecurityManager:相当于SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;它管理着所有Subject、且负责进行认证和授权、及会话、缓存的管理。


Authenticator:认证器;


Authrizer:授权器,;


Realm:可以有1个或多个Realm,是安全实体数据源;可以是JDBC实现,也可以是LDAP实现,或者内存实现等等;


SessionManager:**Shiro自己的Session来管理主体与应用之间交互的数据;


SessionDAO:**DAO大家都用过,数据访问对象,用于会话的CRUD;同时SessionDao也可以使用Cache进行缓存以提高性能。


CacheManager:缓存控制器,管理如用户、角色、权限等的缓存


Cryptography:密码模块


helloshiro

导入相关依赖:官方依赖


 

    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-core</artifactId>
        <version>1.6.0</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-log4j12</artifactId>
        <version>1.7.21</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
 <resources>
                <resource>
                    <directory>${basedir}/src/main/webapp</directory>
                </resource>
                <resource>
                    <directory>${basedir}/src/main/resources</directory>
                </resource>
                <resource>
                    <directory>${basedir}/src/main/java</directory>
                    <includes>
                        <include>**/*.xml</include>
                        <include>**/*.properties</include>
                        <include>**/*.yml</include>
                    </includes>
                </resource>
            </resources>

修改后的Quickstart类,


最新版本建议将:


FactorySecurityManager factory = new IniSecurityManagerFactory(classpath:shiro.ini);
SecurityManager securityManager = factory.getInstance();
转换位下面这样
DefaultSecurityManager securityManager = new DefaultSecurityManager();
IniRealm iniRealm = new IniRealm(classpath:shiro.ini);
securityManager.setRealm(iniRealm);


下面代码是Quickstart类:

/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.text.IniRealm;
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):
        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);
        // 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 currentUser = SecurityUtils.getSubject();
        // Do some stuff with a Session (no need for a web or EJB container!!!)
        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:
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } 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:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }
        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
            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("winnebago:drive:eagle5")) {
            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!
        currentUser.logout();
        System.exit(0);
    }
} 

三大对象:


Subject

SecurityManage

realm


shiro整个流程

常用过滤器如下


anon:无需认证访问

authc:必须认证了才能访问

user:记住我开启了,才可以用

perms:拥有对某个资源的权限才能访问

role:该资源必须得到角色权限才可以访问

代码实战:


首先是shiroconfig,我们从下往上配置:


首先是创建一个realm类

之后是创建shiroconfig

之后从下往上配置

首先是引入realm类

配置安全管理器

之后设置过滤工厂

package com.hyc.config;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.Map;
@Configuration
public class shrioconfig {
//    shirofilterfactoryBean
     @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*
            * 常用过滤器如下
            * anon:无需认证访问
            * authc:必须认证了才能访问
            * user:记住我开启了,才可以用
            * perms:拥有对某个资源的权限才能访问
            * */
            * */
         Map<String,String> filter = new LinkedHashMap();
         filter.put("/add","anon");
         filter.put("/upd","authc");
         bean.setFilterChainDefinitionMap(filter);
         bean.setLoginUrl("/tologin"); 
         return bean;
        }
//    dafultwebSecurityManager
    @Bean(name="SecurityManager")
public DefaultWebSecurityManager getdefaultWebSecurityManager(@Qualifier("Userrealm") userrealm userrealm){
    DefaultWebSecurityManager SecurityManager = new DefaultWebSecurityManager();
//    关联Userrealm
    SecurityManager.setRealm(userrealm);
    return  SecurityManager;
}
    //    创建realm对象,需要自定义类
    @Bean
    public userrealm Userrealm() {
    return new userrealm();
    }
}

realm对象需要引用外面的类 userrealm,我们需要继承AuthorizingRealm来获得授权,认证方法

package com.hyc.config;
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;
public class userrealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权=========>");
        return null;
    }
    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证=========>");
        return null;
    }
}

用户认证:

我们需要去编写config类,设置权限,什么路径需要什么权限,


  @Bean
        public ShiroFilterFactoryBean shiroFilterFactoryBean(@Qualifier("SecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
            /*
            * 常用过滤器如下
            * anon:无需认证访问
            * authc:必须认证了才能访问
            * user:记住我开启了,才可以用
            * perms:拥有对某个资源的权限才能访问
            role:该资源必须得到角色权限才可以访问
            * */
         Map<String,String> filter = new LinkedHashMap();
         filter.put("/user/add","perms[user:add]");
         filter.put("/user/upd","perms[user:upd]");
         bean.setFilterChainDefinitionMap(filter);
         bean.setLoginUrl("/tologin");
         bean.setUnauthorizedUrl("/unauth");
         return bean;
        }

之后去realm去认证,认证的信息是我们从数据库user表中查询出来的数据


  //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("认证=========>");
//        获取当前的用户
        Subject subject = SecurityUtils.getSubject();
//        封装用户数据
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        user user = userService.queryUserByName(token.getUsername());
        if (user==null){
            return null;
        }
        //认证的时候创建用户登陆的session
        Session session = subject.getSession();
                //将用户的属性传入到session中
        session.setAttribute("loginUser",user);
    //如何让我们的user可以全局使用,我们需要设置info中第一个参数为user
        return new SimpleAuthenticationInfo(user,user.getPassword() ,"");
    }

之后再认证之后获取用户对象授权,什么对象可以访问什么页面

    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("授权=========>");
        //授权信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //传递用户信息
        Subject subject = SecurityUtils.getSubject();
        user currentUser = (user) subject.getPrincipal();
        //从数据库中获取授权角色
        info.addStringPermission(currentUser.getParms());
        info.addRole("user:add");
        info.addRole("user:upd");
        return info;
    }

登陆功能

controller

    @RequestMapping("/login")
    public String login(String username,String password,Model model){
        //获取角色对象
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        try {
            subject.login(token);//判断令牌是否正确
            return "index";
        } catch (UnknownAccountException uae) {//用户名不存在
            model.addAttribute("msg","用户名不存在");
            return "login";
        } catch (IncorrectCredentialsException ice) {//密码不存在
            model.addAttribute("msg","密码错误");
            return "login";
        }
    }

这里有一个拓展可以做:就是密码加密处理


我们这里调用的login()方法会走上面我们配置的一系列流程



相关文章
|
6天前
|
缓存 监控 Java
|
6天前
|
缓存 监控 Java
|
28天前
|
安全 Java 数据库
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
这篇文章是关于Apache Shiro权限管理框架的详细学习指南,涵盖了Shiro的基本概念、认证与授权流程,并通过Spring Boot测试模块演示了Shiro在单应用环境下的使用,包括与IniRealm、JdbcRealm的集成以及自定义Realm的实现。
38 3
shiro学习一:了解shiro,学习执行shiro的流程。使用springboot的测试模块学习shiro单应用(demo 6个)
|
28天前
|
Java 数据库连接 Maven
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和MyBatis Generator,使用逆向工程来自动生成Java代码,包括实体类、Mapper文件和Example文件,以提高开发效率。
84 2
mybatis使用一:springboot整合mybatis、mybatis generator,使用逆向工程生成java代码。
|
13天前
|
安全 Java 编译器
springboot 整合表达式计算引擎 Aviator 使用示例详解
本文详细介绍了Google Aviator 这款高性能、轻量级的 Java 表达式求值引擎
|
1月前
|
前端开发 Java Apache
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
本文详细讲解了如何整合Apache Shiro与Spring Boot项目,包括数据库准备、项目配置、实体类、Mapper、Service、Controller的创建和配置,以及Shiro的配置和使用。
240 1
Springboot整合shiro,带你学会shiro,入门级别教程,由浅入深,完整代码案例,各位项目想加这个模块的人也可以看这个,又或者不会mybatis-plus的也可以看这个
|
26天前
|
Java BI API
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
这篇文章介绍了如何在Spring Boot项目中整合iTextPDF库来导出PDF文件,包括写入大文本和HTML代码,并分析了几种常用的Java PDF导出工具。
288 0
spring boot 整合 itextpdf 导出 PDF,写入大文本,写入HTML代码,分析当下导出PDF的几个工具
|
28天前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
6天前
|
JavaScript NoSQL Java
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
CC-ADMIN后台简介一个基于 Spring Boot 2.1.3 、SpringBootMybatis plus、JWT、Shiro、Redis、Vue quasar 的前后端分离的后台管理系统
23 0
|
27天前
|
NoSQL Java Redis
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。
这篇文章介绍了如何使用Spring Boot整合Apache Shiro框架进行后端开发,包括认证和授权流程,并使用Redis存储Token以及MD5加密用户密码。
22 0
shiro学习四:使用springboot整合shiro,正常的企业级后端开发shiro认证鉴权流程。使用redis做token的过滤。md5做密码的加密。