欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

shiro-springboot集成

程序员文章站 2022-03-15 09:54:33
1.shiro-springboot集成的优势: 方便了対用户权限的管理,和対用户权限进行鉴权1.1创建shiro-springboot工程1.2引入依赖 org.springframework.boot spring-boot-starter-parent ...

1.shiro-springboot集成的优势: 方便了対用户权限的管理,和対用户权限进行鉴权

1.1创建shiro-springboot工程

shiro-springboot集成

1.2引入依赖

  <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.0.RELEASE</version>

    </parent>
 <dependencies>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--springboot集成Junit 的启动依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
            <exclusions>
                <exclusion>
                    <groupId>org.junit.vintage</groupId>
                    <artifactId>junit-vintage-engine</artifactId>
                </exclusion>
            </exclusions>
        </dependency>


        <!--thymeleaf启动依赖,它是一个前端模板引擎,完全替代jsp-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
        <!--引入的是shiro与spring的集成-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.4.1</version>
        </dependency>





        <!--aop 的起步依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>


        <!-- web相关依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- test相关依赖-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
        </dependency>
        <!-- 阿里巴巴的Druid数据源依赖启动器 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!-- MyBatis依赖启动器 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- MySQL数据库连接驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

    </dependencies>



3.创建com.aaa.springboot根目录,并在当前包下面创建启动器MyApplication

1.3注意:MyApplication启动器必须在根目录下创建,否则会有问题

@SpringBootApplication   //标记当前类是一个springboot启动类,注意一个应用只有一个启动类;
//注意一个应用只有一个启动类
//启动类要放在根目录,只有两个目录,springboot 应用才会扫描到对应的controller  , service  ,dao  ,entity层里的东西.
public class MyApplication {
    public static void main(String[] args) {
        //启动springboot应用
        SpringApplication.run(MyApplication.class,args);
    }
}

1.4 com.aaa.springshiro.realm

package com.aaa.springshiro.realm;

import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 *  认证 + 授权
 */
public class UserRealm extends AuthorizingRealm {

    // 获取认证信息
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        String username = (String) authenticationToken.getPrincipal();
        System.out.println("username=="+username);


        // 需要自己取数据库校验当前用户名是否存在 如果不存在,用改手动方式抛出
        if (!username.equals("root")){
            throw  new UnknownAccountException();
        }


        // 根据据用户名 去数据库查询密码
        // 假装去数据获取对应用户名的密码
        String passwordFromDB = "123456";

        // 得到用户  真实的数据哭的用户名 密码认证信息
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,passwordFromDB,this.getName());

        //返回给securityMange 进行认证
        return authenticationInfo;
    }

    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        String username = (String) principalCollection.getPrimaryPrincipal();

        System.out.println("username:"+username);


        SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
        // 去数据库查询 root 相关的权限 和  角色
        if (username.endsWith("root")){

            // 设置当前用户角色
            authorizationInfo.addRole("boss");

            // 给当前用户设置权限
            authorizationInfo.addStringPermission("goods:add");
            authorizationInfo.addStringPermission("goods:delete");
            authorizationInfo.addStringPermission("user:delete");


        }

        // 返回个securityManager 当前用户的角色 和权限
        return authorizationInfo;
    }


}

1.5 com.aaa.springshiro.config

package com.aaa.springshiro.config;

import com.aaa.springshiro.realm.UserRealm;
import org.apache.shiro.authz.annotation.*;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver;

import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * ClassName:ShiroConfig
 * Package:com.aaa.springshiro.config
 * Description:
 *
 * @date:2020/7/29 18:53
 * @author:lee907463383@qq.com
 */
@Configuration    //表明当前是一个配置类   相当于  bean.xml文件
public class ShiroConfig {
    @Bean    //1.将创建的UserRealm 加入到容器
    public UserRealm getUserRealm(){
        UserRealm userRealm = new UserRealm();
        return userRealm;
    }

    @Bean  //2.将SecurityManager加入容器,    把UserRealm  和  SecurityManager绑定到一起快
           // 当容器创建SecurityManager 时, 会去 容器中查找一个UserRealm类型的bean
    public SecurityManager getSecurityManager(UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    @Bean //3.设置shiro 过滤器:作用就是过滤拦截,鉴权当前用户是否有 对应的角色和权限
    //把ShiroFilterFactoryBean加入容器,并且与SecurityManager绑定到一起
    public  ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //将setSecurityManager与拦截器进行绑定
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 没有登录,当访问时要跳转到登录页面
        shiroFilterFactoryBean.setLoginUrl("/user/toLogin");
        //登陆成功, 自动跳转到主页面;
        shiroFilterFactoryBean.setSuccessUrl("/user/toIndex");
        //当登录后,  但是权限不足的时候, 会自动跳转到该页面.
        shiroFilterFactoryBean.setUnauthorizedUrl("/user/unauthorized");

        //Map对象集合    (key,value)
        //自定义一个Map<String, String>设置

        Map<String, String> filterChainDefinitionMap = new HashMap<>();

        /*anon表示配置不被拦截的连接  顺序判断     */
        // 设置当前路径  不被shiro 拦截

        filterChainDefinitionMap.put("/user/login","anon");

        // 配置游客路径  不拦截  无论是否登陆 都可以访问
        filterChainDefinitionMap.put("/guest/*","anon");

        // 访问当前路径   roles[root]当前必须拥有root角色 ,  roles[root,manager]  当前用户必须拥有 列那个角色
        /*filterChainDefinitionMap.put("/user/add","roles[boss]");*/
        filterChainDefinitionMap.put("/user/add","roles[root]");

        // 访问当前路径 必须拥有 user:delete
        filterChainDefinitionMap.put("/user/delete","perms[user:delete]");



        // 拦截所有路径 *****   一定要写在再最后
        filterChainDefinitionMap.put("/**","authc");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }
    @Bean  //基于注解的权限  鉴权  也就是说不通过上边复杂的方式进行  权限的限定
           //   @RequiresGuest,@RequiresRoles(),@RequiresUser,@RequiresPermissions()@RequiresAuthentication
    //通知Advisor  AOP.相当于<!-- 开启aop asjpectj 功能-->
    //<aop:aspectj-autoproxy/>
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager){

        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        // //将setSecurityManager与拦截器进行绑定
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }
    @Bean// <aop:aspectj-autoproxy/> 开启aop 注解,像容器注入一个 DefaultAdvisorAutoProxyCreator
    @ConditionalOnMissingBean
    DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =
                new DefaultAdvisorAutoProxyCreator();
        // 使用cglib 完成代理
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /*这里的异常是从前台抓取的,你要记得你是后台,你要学会从后台抓取,如何抓?  这是个提升*/
    @Bean  //当前异常处理的就是  shiro 基于注解鉴权时,  不满足权限时需要抓住异常,因为不是所有的都会自动去403页面
          //比如:GoodsController,FirstController中注解引起的错误,需要抓取异常;
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver =
                new SimpleMappingExceptionResolver();

        //Properties  就是读取配置文件的键対值

        Properties property = new Properties();

        //key 就是要捕捉异常的  全限定名
        property.setProperty("org.apache.shiro.authz.AuthorizationException","/403.html");

        resolver.setExceptionMappings(property);
        return resolver;


    }

}

1.6 com.aaa.springshiro.controller.UserController

package com.aaa.springshiro.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * ClassName:UserController
 * Package:com.aaa.springshiro.controller
 * Description:
 *
 * @date:2020/7/29 19:15
 * @author:lee907463383@qq.com
 */
@Controller
@RequestMapping("/user")
public class UserController{
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    @RequestMapping("/toIndex")
    public String toIndex(){
        return "index";
    }

    @RequestMapping("/login")
    public String login(String username,String password){
        Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(username,password);

        subject.login(token);

        if (subject.isAuthenticated()){
            return "index";
        }else {
            return "login";
        }
    }
    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        if (subject.isAuthenticated()){
            subject.logout();
        }
        return "login";
    }
    @RequestMapping("/unauthorized")
    public String unauthorized(){
        return "403";
    }

    @RequestMapping("/add")
    public  String userAdd(){
        return "addUser";
    }
    @RequestMapping("/delete")
    public  String userdelete(){
        return "deleteUser";
    }
}

1.7src/main/resources

403.html  <h2>无访问权限</h2>
addgoods.html  <h2>addgoods</h2>
addUser.html   <h2>addUser</h2>
deletegoods.html  <h2>deletegoods</h2>
deleteUser.html   <h2>deleteUser</h2>
goodslist.html   <h2>显示所有商品</h2>
index.html 
 <a href="/user/add">新增</a>
<a href="/user/logout">退出</a>

<div>
    <a href="/goods/getGoodsList">显示所有商品 </a>
    <a href="/goods/addGoods">添加商品 </a>
    <a href="/goods/deleteGoods">删除商品 </a>

</div>
<a href="/user/delete">删除</a>
<a href="/guest/first2">游客</a>

login.html
      <form action="/user/login" method="get">
          账号: <input type="text" name="username">
          密码: <input type="password" name="password">
          <input type="submit"value="登录">
      </form>
      <a href="/guest/first2">游客</a>
message.html  <h2>message</h2>

2.如何设置:当没有权限的时候,跳转到403路径的几种情况;

总结:因为开始没配置shiro的注解配置,所以图1-1 —> 图1-6只是基本的shiro配置,这里讲了会出现的几种情况.
但是后边用到了shiro注解的配置,却产生了权限不足时发生的不会自动跳转到403.html页面的异常,所以引入容器中了
解决授权无法捕获异常的异常,
以前通知是写在切面(AspectJ中),这里只写了一个通知
@RequiresGuest 注意授权的url必须在过滤器中被拦截
注意点: 这是个坑
1.当前用户如果被认证,不能访问
2.配置当前路径必须在ShiroFilterFactoryBean声明当前路径为 anon
shiro里边的一个坑,因为shiro要求,访问必须登录,但是
顾客访问不需要登录,所以要满足第二点.
shiro-springboot集成

图1-1的效果如何实现??? 通过图1-2,1-3,1-4,1-5来描述

shiro-springboot集成

图1-2 展示的是没有controller,有权限

shiro-springboot集成

图1-3 展示的是没权限,有controller

shiro-springboot集成

图1-4展示的是有权限,有controllershiro-springboot集成

图1-5 展示的是添加了拦截器, 判断是否有role 和 权限, 这里三个异常情况(图1-7下有一个)

1.如果没有设置controller就会报错,
2.如果没有设置跳转的页面也会报错,这个异常需要抓取出来,并且当发生时,需要跳转到403页面.

shiro-springboot集成

图1-6 没有设置Realm的权限,或者设置了ShiroConfig拦截,Realm中却没有该权限.都不会弹500,会直接展示没有权限

shiro-springboot集成

图1-7 使用shiro注解时,如果用户Realm中没有设置该权限,那么访问的时候会报错.如何解决?通过异常的抓取去展示异常 图1-8可以解决该问题.shiro-springboot集成shiro-springboot集成

图1-8 解决授权无法捕获的问题

shiro-springboot集成

3.使用注解完成shiro的权限和鉴权简单操作: 需要引入AOP依赖

 @Bean  //基于注解的权限  鉴权  也就是说不通过上边复杂的方式进行  权限的限定
           //   @RequiresGuest,@RequiresRoles(),@RequiresUser,@RequiresPermissions()@RequiresAuthentication
    public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager){

        AuthorizationAttributeSourceAdvisor attributeSourceAdvisor =
                new AuthorizationAttributeSourceAdvisor();
        // //将setSecurityManager与拦截器进行绑定
        attributeSourceAdvisor.setSecurityManager(securityManager);
        return attributeSourceAdvisor;
    }
    @Bean// <aop:aspectj-autoproxy/> 开启aop 注解,像容器注入一个 DefaultAdvisorAutoProxyCreator
    //通知Advisor  AOP.相当于<!-- 开启aop asjpectj 功能-->  <aop:aspectj-autoproxy/>
    @ConditionalOnMissingBean
    DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator =
                new DefaultAdvisorAutoProxyCreator();
        // 使用cglib 完成代理
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

com.aaa.springshiro.controller.GoodsController

@Controller
@RequestMapping("/goods")
public class GoodsController {

/*
 *@Author lee
 *@time:2020/7/29 21:15
 *注释:在goods控制层展示的注解;
 */

    @RequiresAuthentication// 只要当前  用户登陆就可以查看
    @RequestMapping("/getGoodsList")
    public String getGoodsList(){

        return "goodslist";
    }



    @RequestMapping("/addGoods")
    @RequiresPermissions("goods:add")//  要求访问当前路径 必须有goods:add 权限
    public String addGoods(){

        return "addgoods";
    }

    @RequestMapping("/deleteGoods")
    @RequiresRoles("root")  //要求访问当前 路径必须时boss
    public String deleteGoods(){
        return "deletegoods";
    }



}

com.aaa.springshiro.controller.FirstController

package com.aaa.springshiro.controller;
import org.apache.shiro.authz.annotation.RequiresGuest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping("/guest")
public class FirstController {
    @RequestMapping("/first")
    public String first(){

        return "message";
    }
    @RequiresGuest
    //1.要求当前用户是游客状态,必须是未登录 如果一定能路报错 注意当前/guest/first2
    //2.必须filterChainDefinitionMap  设置当前路径为 anon 不拦截转台
    @RequestMapping("/first2")
    public String first2(){

        return "message";
    }

}

4. 抓取异常 抓取异常有三种方式,这里采用抓取前台异常的方式,去获取异常

/*这里的异常是从前台抓取的,你要记得你是后台,你要学会从后台抓取,如何抓?  这是个提升*/
    @Bean  //当前异常处理的就是  shiro 基于注解鉴权时,  不满足权限时需要抓住异常,因为不是所有的都会自动去403页面
          //比如:GoodsController,FirstController中注解引起的错误,需要抓取异常;
    public SimpleMappingExceptionResolver getSimpleMappingExceptionResolver(){
        SimpleMappingExceptionResolver resolver =
                new SimpleMappingExceptionResolver();

        //Properties  就是读取配置文件的键対值

        Properties property = new Properties();

        //key 就是要捕捉异常的  全限定名
        property.setProperty("org.apache.shiro.authz.AuthorizationException","/403.html");

        resolver.setExceptionMappings(property);
        return resolver;

    }

shiro-springboot集成
shiro-springboot集成
shiro-springboot集成
shiro-springboot集成

本文地址:https://blog.csdn.net/nnnnnnnnnnii/article/details/107681184