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(),"");
  }
}

 

 

原文地址:https://www.cnblogs.com/bxbo/p/13509241.html