• shiro 登录拦截和用户认证、资源授权


    shiro 登录拦截和用户认证、资源授权

    • Apache Shiro是一个强大且易用的Java安全框架,执行身份验证、授权、密码和会话管理。

    • 三个核心组件:Subject, SecurityManager 和 Realms.

      1. Subject   Subject:即“当前操作用发户”。但是,在Shiro中,Subject这一概念并不仅仅指人,也可以是第三方进程、后台帐户(Daemon Account)或其他类似事物。它仅仅意味着“当前跟软件交互的东西”。但考虑到大多数目的和用途,你可以把它认为是Shiro的“用户”概念。Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。

      1. SecurityManager   SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。

      1. Realm   Realm充当了Shiro与应用安全数据间的“桥梁”或者“连接器”。也就是说,当对用户执行认证(登录)和授权(访问控制)验证时,Shiro会从应用配置的Realm中查找用户及其权限信息。   从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。   Shiro内置了可以连接大量安全数据源(又名目录)的Realm,如LDAP、关系数据库(JDBC)、类似INI的文本配置资源以及属性文件等。如果缺省的Realm不能满足需求,你还可以插入代表自定义数据源的自己的Realm实现。

    项目目录结构

     

     

    添加依赖

    pom.xml

    <dependencies>
           <dependency>
               <groupId>org.projectlombok</groupId>
               <artifactId>lombok</artifactId>
               <version>1.16.10</version>
               <scope>provided</scope>
           </dependency>

       <!-- 导入web支持:SpringMVC开发支持,Servlet相关的程序 -->
       <!-- web支持,SpringMVC, Servlet支持等 -->
       <dependency>
           <groupId>org.springframework.boot</groupId>
           <artifactId>spring-boot-starter-web</artifactId>
       </dependency>
           <!-- 导入thymeleaf依赖 -->
           <dependency>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-starter-thymeleaf</artifactId>
           </dependency>
           <!-- shiro与spring整合依赖 -->
           <dependency>
               <groupId>org.apache.shiro</groupId>
               <artifactId>shiro-spring</artifactId>
               <version>1.4.0</version>
           </dependency>

           <!-- 导入mybatis相关的依赖 -->
           <dependency>
               <groupId>com.alibaba</groupId>
               <artifactId>druid</artifactId>
               <version>1.0.9</version>
           </dependency>
           <!-- mysql -->
           <dependency>
               <groupId>mysql</groupId>
               <artifactId>mysql-connector-java</artifactId>
               <version>8.0.18</version>
           </dependency>
           <!-- SpringBoot的Mybatis启动器 -->
           <dependency>
               <groupId>org.mybatis.spring.boot</groupId>
               <artifactId>mybatis-spring-boot-starter</artifactId>
               <version>1.1.1</version>
           </dependency>

           <!-- thymel对shiro的扩展坐标 -->
           <dependency>
               <groupId>com.github.theborakompanioni</groupId>
               <artifactId>thymeleaf-extras-shiro</artifactId>
               <version>2.0.0</version>
           </dependency>
       </dependencies>
       <!-- 修改参数 -->
       <properties>

           <!-- 修改thymeleaf的版本 -->
           <thymeleaf.version>3.0.2.RELEASE</thymeleaf.version>
           <thymeleaf-layout-dialect.version>2.0.4</thymeleaf-layout-dialect.version>
       </properties>

    <!--将xml文件放在src下,访问xml文件资源-->
       <build>
           <resources>
               <resource>
                   <directory>src/main/java</directory>
                   <includes>
                       <include>**/*.xml</include>
                   </includes>
               </resource>
           </resources>
       </build>

     

    整合mybatis

    application.properties

    spring.datasource.driverClassName=com.mysql.cj.jdbc.Driver
    spring.datasource.url=jdbc:mysql://localhost:3306/springbootshiro?characterEncoding=UTF-8&serverTimezone=UTC&useSSL=false
    spring.datasource.username=root
    spring.datasource.password=12


    #数据库连接池的配置
    spring.datasouce.type=com.alibaba.druid.pool.DruidDataSource

    #mybatis别名扫描配置
    mybatis.type-aliases-package=com.bxb.domain

    dao层

    User.java

    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    import lombok.ToString;


    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @ToString
    public class User {
       private Integer id;
       private String name;
       private String password;
       private String perms;
    }

    Mapper

    Usermapper.java

    import com.bxb.domain.User;
    import org.apache.ibatis.annotations.Mapper;

    //@Mapper
    public interface UserMapper {

       User findUserByName(String name);

       User findUserById(Integer id);
    }

    UseMapper.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.bxb.Mapper.UserMapper">
       <select id="findUserByName" parameterType="string" resultType="user">
          select *
          from user
          where name=#{name}
       </select>

       <select id="findUserById" parameterType="integer" resultType="user">
          select *
          from user
          where id=#{id}
       </select>
    </mapper>

    Service

    UserService.java

    public interface UserService {
       User findByName(String name);
       User findById(Integer id);
    }

    UserServiceImpl

    UserServiceImpl.java

    @Service
    public class UserServiceImpl implements UserService {

       @Autowired
       private UserMapper userMapper;
       @Override
       public User findByName(String name) {
           return userMapper.findUserByName(name);
      }

       @Override
       public User findById(Integer id) {
           return userMapper.findUserById(id);
      }
    }

    前端页面

    login.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
       <meta charset="UTF-8">
       <title>登录</title>
    </head>
    <body>
    <h3>登录</h3>
    <h3 th:text="${msg}" style="color:red"></h3>
    <form method="post" action="login">
      用户名:<input type="text" name="name"/></br>
      密码:<input type="password" name="password"/></br>
       <input type="submit" value="登录"/>

    </form>
    </body>
    </html>

    test.html

    <!DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
           xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro">
    <head>
       <meta charset="UTF-8">
       <title>测试</title>
    </head>
    <body>
    <h3 th:text="${name}"></h3>

    <hr/>
    <div th:if="${session.loginUser==null}">
       <a href="toLogin">登录</a>
    </div>
    <div shiro:hasPermission="user:add">
    用户添加:<a href="add">添加</a>
    </div>
    <hr/>
    <div shiro:hasPermission="user:update">
    用户修改:<a href="update">修改</a>
    </div>
    </body>
    </html>

    noAuth.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
       <meta charset="UTF-8">
       <title>未授权提示页面</title>
    </head>
    <body>
    你还没有经过授权!!!
    </body>
    </html>

     

    shiro配置文件

    shiroConfig.java

    import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
    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.Map;

    @Configuration
    public class ShiroConfig {

       /**
        * 创建ShiroFilterFactoryBean
        */
       @Bean
       public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
           ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
           //关联安全管理器
           shiroFilterFactoryBean.setSecurityManager(securityManager);
           /**
            * Shiro内置过滤器,可以实现权限相关的拦截器
            * 常用的过滤器:
            *     anon:无需认证(登录)可以访问
            *     authc:必须认证才能访问
            *     user:如果使用rememberMe的功能才可以直接访问
            *     perms:该资源必须得到资源权限才可以访问
            *     role:该资源必须得到角色权限才可以访问
            */

           Map<String, String> filterMap=new LinkedHashMap<String, String>();
    //       filterMap.put("/add","authc");
    //       filterMap.put("/update","authc");
           filterMap.put("/testThymeleaf","anon");
           filterMap.put("/login","anon");
           //授权过滤器
           //注意:当前授权拦截后,shiro会自动跳转到未授权页面
           filterMap.put("/add","perms[user:add]");
           filterMap.put("/update","perms[user:update]");
           filterMap.put("/*","authc");

           //修改调整的登录界面
           shiroFilterFactoryBean.setLoginUrl("/toLogin");//拦截成功跳转的登录界面
           //设置未授权的提示页面
           shiroFilterFactoryBean.setUnauthorizedUrl("/noAuth");
           shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);
           return shiroFilterFactoryBean;
      }

       /**
        * 创建DefaultWebSecuityManager
        *@Qualifier注解的用处:当一个接口有多个实现的时候,为了指名具体调用哪个类的实现
        */
           @Bean(name="securityManager")
           public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
               DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
               //关联realm
               securityManager.setRealm(userRealm);
               return securityManager;
          }


       /**
        * 创建Realm
        */
       @Bean(name="userRealm")  //将方法返回的对象放入spring环境
       public UserRealm getRealm(){
           return new UserRealm();
      }

       /**
        * 配置ShiroDialect,用于thymeleaf和shiro标签配合使用
        */
       @Bean
       public ShiroDialect getShiroDialect(){
           return new ShiroDialect();
      }
    }

    UserRealm.java

    import com.bxb.Service.UserService;
    import com.bxb.domain.User;
    import org.apache.shiro.SecurityUtils;
    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;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;

    import java.awt.*;

    import static java.awt.SystemColor.info;

    /**
    * 自定义Realm
    */
    public class UserRealm extends AuthorizingRealm {
       /**
        * 执行授权逻辑
        * @param principalCollection
        * @return
        */
       @Override
       protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
           System.out.println("执行授权逻辑");
           //给资源进行授权
           SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();

           //添加资源的授权字符串
           //info.addStringPermission("user:add");

           //到数据库查询当前登录用户的授权字符串
           //获取当前登录用户
           Subject subject = SecurityUtils.getSubject();
           User user= (User) subject.getPrincipal();
           User dbuser=userService.findById(user.getId());
           info.addStringPermission(dbuser.getPerms());
    //       info.addStringPermission(user.getPerms());
           return info;
      }

       /**
        * 执行认证逻辑
        * @param authenticationToken
        * @return
        * @throws AuthenticationException
        */

       @Autowired
       private UserService userService;
       @Override
       protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
           System.out.println("执行认证逻辑");

           //假设数据库的用户名和密码
    //       String name="aaa";
    //       String password="123";
           //编写shiro判断逻辑,判断用户名和密码
           //1.判断用户名
           UsernamePasswordToken token= (UsernamePasswordToken) authenticationToken;
           User user = userService.findByName(token.getUsername());
           Subject currentSubject = SecurityUtils.getSubject();
           Session session = currentSubject.getSession();
           session.setAttribute("loginUser",user);

           if(user==null){
               //用户名不存在
               return null;//shiro底层会抛出UnKnowAccountException
          }
           //判断密码
           return new SimpleAuthenticationInfo(user,user.getPassword(),"");
      }
    }

     

     

  • 相关阅读:
    js中实现继承的几种方式
    js中prototype,__proto__,constructor之间的关系
    圣杯布局
    BFC详解
    Altium制作DC002的PCB封装和3D模型
    直流供电电路中,关于电源并联二极管、电容作用的思考与总结
    AltiumDesigner17快捷键
    AltiumDesigner17学习指南
    AltiumDesigner元器件搜索中英文对照
    智慧树自动刷课脚本
  • 原文地址:https://www.cnblogs.com/bxbo/p/13509241.html
Copyright © 2020-2023  润新知