Shiro学习与笔记

Shiro

  • Shiro
    • Shiro理论
      • 什么是shiro
      • 功能
      • 组件
      • shiro注解
      • shiro的优点
      • 运行流程
      • 前端标签
        • jsp页面
        • Thymeleaf
    • 在spring框架中集成shiro
      • Pom文件进行依赖配置
      • 集成Shiro
        • web.xml中的设置
        • shiro的bean配置文件,
    • Spring Boot Shiro
      • POM文件
      • 在application.properties设置shiro配置
      • MyRealm.java
      • ShiroConfig.java
      • 身份验证
        • Role 配合页面标签,控制不同用户访问不同页面
        • Resource 配合控制器注解,控制某个特殊的授权权限

Shiro

Shiro理论

什么是shiro

Shiro是一个强大易用的java安全,提供了认证、授权、加密、会话管理、与web集成、缓存等功能,对于任何一个应用程序,都可以提供全面的安全服务,相比其他安全框架,shiro要简单的多。

功能

  • 身份验证(核心功能);
  • 资源授权(核心功能);
  • 密码加密(非核心功能);
  • 会话管理(非核心功能);
  • Remember Me(非核心功能);

组件

  • Subject:应用层和shiro框架交互的对象
  • Realm:实现身份验证和资源授权的核心组件:域,shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。
  • RememberMeManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是shiro的核心, SecurityManager相当于spring mvc中的dispatcherServlet前端控制器。
    • SimpleCookie:记住我——Cookie
    • CookieRememberMeManager:记住我—— Cookie 管理器;
  • SessionManager
    • SimpleCookie:会话管理—— Cookie
    • DefaultWebSessionManager:会话配置;
  • SecurityManager:安全管理器,它负责与 Shiro 的其他组件进行交互,需要注入 RealmRememberMeManagerSessionManager 等组件,且管理着所有的 Subject;
  • ShiroFilterFactoryBeanShiro 过滤器工厂,注入 SecurityManager、定义过滤器、指定路径拦截规则等;
  • ShiroDialect:Shiro 方言,支持 Thymeleaf 页面 Shiro 标签;
  • DefaultAdvisorAutoProxyCreator:Advisor 代理类生成器;
  • AuthorizationAttributeSourceAdvisor:创建 Advisor 代理类,扫描 Shiro 注解;
  • 应用代码通过 Subject 来进行认证和授权,Subject 委托给 SecurityManager,我们需要给 Shiro 的 SecurityManager 注入 Realm,从而让 SecurityManager 能对用户及其权限进行判断;

Shiro学习与笔记_第1张图片

shiro注解

  • @RequiresAuthentication : 表示当前 Subject 需要登录;
  • @RequiresUser : 表示当前 Subject 需要登录或记住我;
  • @RequiresGuest : 表示当前 Subject 是游客身份;
  • @RequiresRoles(value={“admin”, “user”}, logical=Logical.AND):当前 Subject 需要的角色;
  • @RequiresPermissions (value={““,””}, logical= Logical.OR) :当前 Subject 需要拥有的资源;

既可以用在controller中,也可以用在service中建议将shiro注解放入controller,因为如果service层使用了spring的事物注解,那么shiro注解将无效

shiro的优点

1、 简单的身份验证,支持多种数据源
2、对角色的简单授权,支持细粒度的授权(方法)
3、支持一级缓存,以提升应用程序的性能
4、内置基于POJO的企业会话管理,适用于web及非web环境
5、非常简单的API加密
6、不跟任何框架绑定,可以独立运行

运行流程

  1. 首先调用 Subject.login(token) 进行登录,其会自动委托给 Security Manager,调用之前必须通过 SecurityUtils.setSecurityManager() 设置;
  2. SecurityManager 负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
  3. Authenticator 才是真正的身份验证者,Shiro API 中核心的身份认证入口点,此处可以自定义插入自己的实现;
  4. Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证,默认 ModularRealmAuthenticator 会调用 AuthenticationStrategy 进行多 Realm 身份验证;
  5. Authenticator 会把相应的 token 传入 Realm,从 Realm 获取身份验证信息,如果没有返回 则抛出异常表示身份验证失败了。此处可以配置多个 Realm,将按照相应的顺序及策略进行访问。

前端标签

jsp页面

首先要导入标签库;
<%@ taglib uri="http://shiro.apache.org/tags" prefix="shiro" %>:导入标签库;
    
:游客访问;
    
:用户需要登录或记住我;
    
:用户需要登录;
    
:用户需要拥有某种角色访问;
    
:用户需要拥有某些角色;
    
:用户需要拥有某资源;进行显示
    

Thymeleaf

导入
<html 
       xmlns:shiro="http://www.pollix.at/thymeleaf/shiro"
      >
    
html>

shiro:guest:游客访问;
shiro:user:用户需要登录或记住我;
shiro:authenticated:用户需要登录;
shiro:hasRole:用户需要某角色;
shiro:hasAnyRoles:用户需要某些角色;
shiro:hasPermission:用户需要某权限;
-----------------------------------------------------------
<li shiro:hasAnyRoles="admin,manager">:用户需要 admin 或 manager 角色可访问;
    
<li><span shiro:principal/>li>:身份验证器包装的用户名时,页面获取用户名;

<span shiro:principal property="loginName"/>:身份验证器中包装 user 对象时,页面获取用户名;

<input type="hidden" id="userId" th:value="${session.user.userId}">:页面获取 session 中 user 对象;

在spring框架中集成shiro

Pom文件进行依赖配置

可以在maven仓库包https://mvnrepository.com/,根据三要素进行查找


<properties>
    <shiro.version>1.7.1shiro.version>
properties>

    <dependency>
      <groupId>org.apache.shirogroupId>
      <artifactId>shiro-coreartifactId>
      <version>${shiro.version}version>
    dependency>


    <dependency>
      <groupId>org.apache.shirogroupId>
      <artifactId>shiro-springartifactId>
      <version>${shiro.version}version>
    dependency>


<dependency>
  <groupId>org.apache.shirogroupId>
   <artifactId>shiro-webartifactId>
   <version>${shiro.version}version>
dependency>


<dependency>
  <groupId>org.apache.shirogroupId>
   <artifactId>shiro-aspectjartifactId>
   <version>${shiro.version}version>
dependency>


<dependency>
  <groupId>org.apache.shirogroupId>
   <artifactId>shiro-ehcacheartifactId>
   <version>${shiro.version}version>
dependency>

项目跑起来了,只是控制台输出了

SLF4J: Failed to load class "org.slf4j.impl.StaticLoggerBinder".
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See http://www.slf4j.org/codes.html#StaticLoggerBinder for further details.

需要配置日志包

shiro使用slf4j作为日志框架,所以必需配置slf4j。同时,使用log4j作为底层的日志实现框架。


  org.slf4j
  slf4j-api
  1.7.25


  org.slf4j
  slf4j-log4j12
  1.7.25


  log4j
  log4j
  1.2.17

集成Shiro

在Spring框架中集成Shiro,本质上是与Spring IoC容器和Spring MVC框架集成.

web.xml中的设置

  
  <filter>
    <filter-name>shiroFilterfilter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxyfilter-class>
    
    
    <init-param>
      <param-name>targetFilterLifecycleparam-name>
      <param-value>trueparam-value>
    init-param>
  filter>
  <filter-mapping>
    <filter-name>shiroFilterfilter-name>
    <url-pattern>/*url-pattern>
  filter-mapping>

shiro的bean配置文件,

其中包含过滤设置。此文件名为spring-shiro.xml,里面定义了需要的Bean,完成诸多功能。



<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.3.xsd

">   
    
    <context:component-scan base-package="com.qq"/>
    
     
    <bean id="userRealm" class="com.qq.realm.UserRealm"/>
    
    
    <bean id="advisorAutoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        
        <property name="proxyTargetClass" value="true"/>
    bean>
    
    
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor" />

    
    
     
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/> 
    bean>
    
    
       <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">

        <property name="realm" ref="userRealm"/>
    bean>
    
    
     
    
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        
      <property name="securityManager" ref="securityManager"/>

      
        
        <property name="loginUrl" value="/login/view"/>

          
        <property name="unauthorizedUrl" value="/login/view" />

        
        
        
        
        <property name="successUrl" value="/home"/>

        

        
        
        <property name="filterChainDefinitions" >
            <value>
                /login/view = anon
                /back/student/zzz =authc,roles[admin]
                /back/** = authc
            value>
        property>


   
beans>


或者:springShiro.xml




<beans xmlns="http://www.springframework.org/schema/beans" 

    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

    xmlns:context="http://www.springframework.org/schema/context" 

    xsi:schemaLocation="http://www.springframework.org/schema/beans 

            http://www.springframework.org/schema/beans/spring-beans-4.0.xsd 

            http://www.springframework.org/schema/context  

            http://www.springframework.org/schema/context/spring-context-4.0.xsd"

    default-lazy-init="true">

    

    

    <bean id="myRealm" class="com.sfac.springMvc.config.MyRealm" />

    

    

    <bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">

        <property name="name" value="rememberMe"/>

        <property name="maxAge" value="604800"/>

        <property name="httpOnly" value="true"/>

    bean>

    <bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">

        <property name="cookie" ref="rememberMeCookie"/>

    bean>

    

    

    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">

        

        <property name="globalSessionTimeout" value="6000000"/>

        

        <property name="deleteInvalidSessions" value="true"/>

        

        <property name="sessionIdUrlRewritingEnabled" value="false" />

    bean>

    

    

    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  

        <property name="realm" ref="myRealm"/>

        <property name="rememberMeManager" ref="rememberMeManager">property>

        <property name="sessionManager" ref="sessionManager" />

    bean>

    

    

    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">

        <property name="securityManager" ref="securityManager"/>

        <property name="loginUrl" value="/login"/>

        <property name="successUrl" value="/common/dashboard"/>

        

        <property name="filterChainDefinitions">  

            <value>  

                /static/**=anon

                /register=anon

                /login=anon

                /forgot=anon

                /logout=logout

                /api/**=anon

                /**=authc

            value>  

        property>  

    bean>

    

    

    

    

    

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"

        depends-on="lifecycleBeanPostProcessor">

        <property name="proxyTargetClass" value="true" />

    bean>

    

    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">

        <property name="securityManager" ref="securityManager" />

    bean>

beans>

必须是在MVC配置文件中用


将spring-shiro.xml载入。

Shiro学习与笔记_第2张图片

例子:

  • 身份验证

    UserRealm

    package com.qq.realm;
    import com.qq.model.User;
    import com.qq.service.UserService;
    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.springframework.beans.factory.annotation.Autowired;
    
    /**
     * @description:com.qq.realm_studyssm
     * @author: 霏宇
     * @time: 2022/8/5,9:55
     */
    public class UserRealm extends AuthorizingRealm {
        @Autowired
        UserService userService;
        //授权:
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
    
            String name =(String)principalCollection.getPrimaryPrincipal();
            if (name.equals("admin")){
                info.addStringPermission("admin");
            }else if (name.equals("lisi")){
                info.addStringPermission("worker");
                info.addRole("admin");
            }
            return info;
    
        }
        /**
         * 认证
         * @param token
         * @return
         * @throws AuthenticationException
         */
    
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
          //一旦此用户不存在就主动抛出异常
            UsernamePasswordToken upToken = (UsernamePasswordToken)token;
             String name =upToken.getUsername();
             String password=new String(upToken.getPassword());
    
             User user =userService.selectByName(name);
             if(null==user){
                 throw new UnknownAccountException("你输入的账户不存在!");
             }else {
                 User user2 =userService.selectByNamePassword(name,password);
                 if(null==user2){
                     throw new IncorrectCredentialsException("密码错误");
                 }else {
                     return  new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());
                 }
             }
    
    //         if(!name.equals("list")&&!name.equals("admin")){
    //             throw new UnknownAccountException("你输入的账户不存在!");
    //         }else {
    //             //这里假设系统的用户只有两个 (zhangsan,123456)、(lisi,888999)
    //             if(name.equals("list")&&password.equals("789") ||name.equals("admin")&&password.equals("123456")){
    //
    //                 return   new SimpleAuthenticationInfo(token.getPrincipal(),token.getCredentials(),this.getName());
    //
    //             }else {
    //                 throw new IncorrectCredentialsException("用户不存在");
    //             }
    //
    //         }
    
    
    
    
        }
    }
    
    

    或者:MyRealm.java

    public class MyRealm extends AuthorizingRealm {
    
        @Autowired
    
        private UserService userService;
    
        @Autowired
    
        private RoleService roleService;
    
        @Autowired
    
        private ResourceService resourceService;
    
    
        /**
    
         * -资源授权器
    
         */
    
        @Override
    
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
    
            // 授权类
    
            SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    
            
    
            User user = (User) principals.getPrimaryPrincipal();
    
            if (user == null) {
    
                return null;
    
            }
    
            
    
            List<Role> roles = Optional
    
                    .ofNullable(roleService.getRolesByUserId(user.getId()))
    
                    .orElse(Collections.emptyList());
    
            roles.stream().forEach(role -> {
    
                authorizationInfo.addRole(role.getRoleName());
    
                List<Resource> resources = Optional
    
                        .ofNullable(resourceService.getResourcesByRoleId(role.getId()))
    
                        .orElse(Collections.emptyList());
    
                resources.stream().forEach(resource -> {
    
                    authorizationInfo.addStringPermission(resource.getPermission());
    
                });
    
            });
    
    
            return authorizationInfo;
    
        }
    
        /**
    
         * -身份验证器
    
         */
    
        @Override
    
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
            String userName = (String) token.getPrincipal();
    
            User user = userService.getUserByUserName(userName);
    
            if (user == null) {
    
                throw new UnknownAccountException("The account do not exist.");
    
            }
    
            
    
            // realmName: 当前 realm 对象的唯一名字. 调用父类的 getName() 方法
    
            return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    
        }
    
    }
    

    LoginController

    package com.qq.controller;
    
    import com.qq.model.User;
    import com.qq.service.UserService;
    import org.apache.shiro.SecurityUtils;
    import org.apache.shiro.authc.IncorrectCredentialsException;
    import org.apache.shiro.authc.UnknownAccountException;
    import org.apache.shiro.authc.UsernamePasswordToken;
    import org.apache.shiro.subject.Subject;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    import org.springframework.ui.Model;
    import org.springframework.web.bind.annotation.RequestMapping;
    
    import javax.servlet.http.HttpSession;
    
    /**
     * @description:com.qq.controller_studyssm
     * @author: 霏宇
     * @time: 2022/8/4,14:02
     */
    @Controller
    @RequestMapping("/login")
    public class LoginController {
        @Autowired
        UserService userService;
        @RequestMapping("/view")
        String index(){
            return "login/view";
        }
    
        @RequestMapping("/enter")
        String enter(String name, String password, HttpSession session, Model model){
    
    
            Subject subject = SecurityUtils.getSubject();     //
            UsernamePasswordToken token = new UsernamePasswordToken(name, password); //对(用户名、密码)登录方式,用UsernamePasswordToken封装即可
            try {
                subject.login(token);	//调用login()方法。 有可能遭遇两种异常,代表登陆失败。
                User user =userService.selectByNamePassword(name,password);
                session.setAttribute("USER",user);
    
            } catch (UnknownAccountException e) {
                e.printStackTrace();
                model.addAttribute("message", "用户名错误!");
                return "redirect:view";
            } catch (IncorrectCredentialsException e) {
                e.printStackTrace();
                model.addAttribute("message", "密码错误");
    
    
                return "redirect:view";
            }
    
            System.out.println(subject.isAuthenticated()); //打印下看看是否已认证成功
    
            return "redirect:/back/hui/index";
    
    
    //        User user = userService.selectByNamePassword(name, password);
    //        if(user==null){
    //
    //            return "redirect:index";
    //        }else {
    //            session.setAttribute("USER", user);
    //            return "redirect:/back/book/index";
    //        }
    
        }
        @RequestMapping("/logout")
        String logout(HttpSession session){
            session.removeAttribute("USER");
             Subject subject =SecurityUtils.getSubject();
             subject.logout();
           // session.invalidate();
            return "redirect:view";
        }
    
    }
    
    

    或者在

    UserService

    public Result<User> login(User user);
    

UserServiceImpl

    ```java
    @Service
    public class UserServiceImpl implements UserService{
        
    @Override
    
    public ResultEntity login(User user) {
    
        Subject subject = SecurityUtils.getSubject();
    
        UsernamePasswordToken token = new UsernamePasswordToken(user.getUserName(), 
    
                MD5Util.getMD5(user.getPassword()));
    
        token.setRememberMe(user.getRememberMe());
        return new Result(Result.ResultStatus.SUCCESS.code, "Success", user);
    
        try {
    
            subject.login(token);
    
            subject.checkRoles();
    
        } catch (Exception e) {
    
            e.printStackTrace();
    
              return new Result(Result.ResultStatus.FAILD.code, e.getMessage());
    
        }
        
        Session session = subject.getSession();
    
        session.setAttribute("user", subject.getPrincipal());
    
        
    
    }
    
    
    @GetMapping("/logout")
    
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
       
        return "redirect:/login";
    
    }
    
    }
    ```

Spring Boot Shiro

POM文件


        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-coreartifactId>
            <version>1.4.0version>
        dependency>
        <dependency>
            <groupId>org.apache.shirogroupId>
            <artifactId>shiro-springartifactId>
            <version>1.4.0version>
        dependency>
        
        
        <dependency>
            <groupId>org.springframework.bootgroupId>
            <artifactId>spring-boot-starter-thymeleafartifactId>
        dependency>
        
        
        <dependency>
            <groupId>com.github.theborakompanionigroupId>
            <artifactId>thymeleaf-extras-shiroartifactId>
            <version>2.0.0version>
        dependency>

在application.properties设置shiro配置

#for shiro
#开启Shiro配置,默认为true
shiro.web.enabled=true

#server.servlet.context-path=/shiro
#spring.application.name=shiro

MyRealm.java

package com.feiyu.sprtingboot.config.shiro;

import com.feiyu.sprtingboot.modules.account.entity.Resource;
import com.feiyu.sprtingboot.modules.account.entity.Role;
import com.feiyu.sprtingboot.modules.account.entity.User;
import com.feiyu.sprtingboot.modules.account.service.ResourceService;
import com.feiyu.sprtingboot.modules.account.service.RoleService;
import com.feiyu.sprtingboot.modules.account.service.UserService;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.List;


/**
 * @description:com.feiyu.sprtingboot.config.shiro_sprtingboot
 * @author: 霏宇
 * @time: 2022/8/31,9:41
 */
@Component
public class MyRealm  extends AuthorizingRealm {
   @Autowired
   private UserService userService;
   @Autowired
   private RoleService roleService;
   @Autowired
   private ResourceService resourceService;

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

        SimpleAuthorizationInfo authorization = new SimpleAuthorizationInfo();

        // 从认证中获取当前的信息
        User user = (User) principals.getPrimaryPrincipal();

        // 从数据库查询当前用户的角色列表,并装载到资源授权器里
        List<Role> roles = roleService.getRolesByUserId(user.getId());
        roles.stream().forEach(item -> {
            authorization.addRole(item.getRoleName());
//            authorization.addStringPermission(item.getRoleName());

            // 再去查询每个角色拥有的资源列表,并装载到资源授权器里
            List<Resource> resources = resourceService.getResourcesByRoleId(item.getId());
            resources.stream().forEach(it -> {
                authorization.addStringPermission(it.getPermission());
                System.out.println(it.getPermission());

            });
        });

        return authorization;
    }

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
            throws AuthenticationException {
        // 获取用户名
        String userName = (String) token.getPrincipal();

        // 通过用户名查找数据库的 user 信息
        User user = userService.getUserByUserName(userName);
        if (user == null) {
            throw new UnknownAccountException("User name is not exit.");
        }

        // 封装身份验证器
        return new SimpleAuthenticationInfo(user, user.getPassword(), getName());
    }
}

ShiroConfig.java

package com.feiyu.sprtingboot.config.shiro;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
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.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @description:com.feiyu.sprtingboot.config.shiro_sprtingboot
 * @author: 霏宇
 * @time: 2022/8/31,10:21
 */
@Configuration
public class ShiroConfig {
    @Autowired
    private MyRealm myRealm;

    @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);

        return securityManager;
    }

    /**
     * anon:匿名访问,无需登录 ---- AnonymousFilter
     * authc:登录后才能访问 ---- FormAuthenticationFilter
     * user:登录过能访问 ---- UserFilter
     * logout:登出 ---- LogoutFilter
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean filterFactory = new ShiroFilterFactoryBean();
        // 注入安全管理器
        filterFactory.setSecurityManager(securityManager());

        // 设置登录页面、登录成功页面
        filterFactory.setLoginUrl("/login");
        filterFactory.setSuccessUrl("/test/thymeleafTest");

        // 设置其余地址的访问策略
        Map<String, String> filterMap = new LinkedHashMap<>();
        // 匿名策略
        // 登录注册
        filterMap.put("/login", "anon");
        filterMap.put("/register", "anon");
        // 静态资源
        filterMap.put("/favicon.ico", "anon");
        filterMap.put("/css/**", "anon");
        filterMap.put("/images/**", "anon");
        filterMap.put("/js/**", "anon");
        filterMap.put("/vendors/**", "anon");
        filterMap.put("/static/**", "anon");
        // 测试模块
        filterMap.put("/test/**", "anon");
        // api
        filterMap.put("/api/**", "anon");

        // 非匿名策略
        filterMap.put("/**", "authc");
        filterFactory.setFilterChainDefinitionMap(filterMap);

        return filterFactory;
    }

    /**
     * - 注册shiro方言,让 thymeleaf 支持 shiro 标签
     */
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }

    @Bean(name="lifecycleBeanPostProcessor")
    public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * DefaultAdvisorAutoProxyCreator, Advisor 代理类生成器
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * - 创建 AuthorizationAttributeSourceAdvisor,扫描 Shiro 注解
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }




}

如果需要加入rememberMeCookie
/**
     * -- Remember Me Cookie
     */
    @Bean

    public SimpleCookie rememberMeCookie() {

        //这个参数是 cookie 的名称

        SimpleCookie simpleCookie = new SimpleCookie("rememberMe");

        //如果 httyOnly 设置为 true,则客户端不会暴露给客户端脚本代码,

        //使用 HttpOnly cookie 有助于减少某些类型的跨站点脚本攻击;

        simpleCookie.setHttpOnly(true);

        //记住我 cookie 生效时间,单位是秒

        simpleCookie.setMaxAge(1 * 24 * 60 * 60);

        return simpleCookie;

    }

   /**
     * -- 管理器
     */

    @Bean
    public CookieRememberMeManager rememberMeManager() {

        CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();

        cookieRememberMeManager.setCookie(rememberMeCookie());

        byte[] cipherKey = Base64.decode("wGiHplamyXlVB11UXWol8g==");

        cookieRememberMeManager.setCipherService(new AesCipherService());

        cookieRememberMeManager.setCipherKey(cipherKey);

        return cookieRememberMeManager;
    }

    /**

     * sessionCookie

     */

    @Bean
    public SimpleCookie sessionCookie() {

        SimpleCookie simpleCookie = new SimpleCookie("shiro.sesssion");

        simpleCookie.setPath("/");

        simpleCookie.setHttpOnly(true);

        simpleCookie.setMaxAge(1 * 24 * 60 * 60);

        return simpleCookie;

    }DefaultWebSessionManager 加入
     /**
     * DefaultAdvisorAutoProxyCreator, Advisor 代理类生成器
     Shiro 默认 Cookie 名称是 JSESSIONID,与 Tomcat 等默认JSESSIONID 冲突,我们需要为 
      Shiro 指定一个不同名称的 Session id,否则抛出 UnknownSessionException: There is no session with id 异常
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
    
         sessionManager.setSessionIdCookie(sessionCookie());
    
        advisorAutoProxyCreator.setProxyTargetClass(true);
       // 相隔多久检查一次 session 的有效性
       // sessionManager.setSessionValidationInterval(1 * 24 * 60 * 60 * 1000);
       // session 有效时间
      // sessionManager.setGlobalSessionTimeout(1 * 24 * 60 * 60 * 1000);
        return advisorAutoProxyCreator;
    }SecurityManager 加入
     @Bean
    public SecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        securityManager.setRememberMeManager(rememberMeManager());
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

身份验证

UserServiceImpl

@Override
    public Result<User> login(User user) {

        // 得到 subject
        Subject subject = SecurityUtils.getSubject();

        // 封装一个登录令牌(装载用户名和密码)
        UsernamePasswordToken token = new UsernamePasswordToken(
                user.getUserName(),
                MD5Util.encode(user.getPassword()));

        try {
            // subject.login()
            subject.login(token);
            subject.checkRoles();
            // 获取当前用户,并将之设置到 session 中
            User temp = (User) subject.getPrincipal();
            Session session = subject.getSession();
            session.setAttribute("user", temp);

            return new Result<User>(Result.ResultStatus.SUCCESS.code, "Success", temp);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.debug(e.getMessage());
            return new Result<User>(Result.ResultStatus.FAILD.code, e.getMessage());
        }

    }

Role 配合页面标签,控制不同用户访问不同页面

 /**
     * 127.0.0.1/account/users---- get
     */
    @RequiresRoles(value = {"admin","manager"},logical = Logical.OR)
    @GetMapping(value = "/account/users")
    public String userPage(ModelMap modelMap) {
        modelMap.addAttribute("template",
                              "account/users");
        return "index";
    }

Resource 配合控制器注解,控制某个特殊的授权权限

 @RequiresPermissions("/api/user/{id}")
    public Result<Object> deleteUserById(@PathVariable int id){
        return userService.deleteUserById(id);

    }

Html页面

 <ul class="nav child_menu">
                <li shiro:hasAnyRoles="admin,manager,staff"><a href="javascript:void(0);">Profilea>li>
                <li shiro:hasAnyRoles="admin,manager"><a href="/account/users">Usersa>li>
                <li shiro:hasAnyRoles="admin,manager"><a href="/account/roles">Rolesa>li>
                <li shiro:hasAnyRoles="admin,manager"><a href="/account/resources">Resourcesa>li>
     ul>


 <ul class="nav child_menu">
                <shiro:hasPermission name="/test/thymeleafTest">
                    <li shiro:hasAnyRoles="admin,manager,staff">
                        <a href="/test/thymeleafTest">ThymeleafTesta>li>
                shiro:hasPermission>
                <shiro:hasPermission name="/test/vueTest">://用户需要拥有某资源;进行显示
                    <li shiro:hasAnyRoles="admin,manager,staff"><a href="/test/vueTest">VueTesta>li>
                shiro:hasPermission>
                <li shiro:hasAnyRoles="admin,manager,staff">
                    <a>二级菜单<span class="fa fa-chevron-down">span>a>
                    <ul class="nav child_menu">
                        <li class="sub_menu"><a href="javascript:void(0);">三级菜单一a>li>
                        <li><a href="javascript:void(0);">三级菜单二a>li>
                    ul>
                li>
            ul>

Shiro学习与笔记_第3张图片

部分转载于http://www.sfac.xyz:8000/notes/Java/Apache_Shiro.html

你可能感兴趣的:(#,JAVA,学习,java,spring)