shiro权限管理实例

1、新建shiro-test工程,选择Spring Web和Thymeleaf依赖
在这里插入图片描述
2、添加相关依赖包

        <!--添加shiro依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>

        <!--添加shiro支持thymeleaf标签依赖-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!--添加shiro EhCache缓存依赖-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.4.2</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

3、在resources下添加ehcache添加ehcache缓存配置文件ehcache.xml
在这里插入图片描述
配置文件如下:

<?xml version="1.0" encoding="UTF-8" ?>
<ehcache>
    <!-- 磙盘的缓存位置-->
    <diskStore path="java.io.tmpdir/ehcache"/>
    <!--默认缓存-->
    <defaultCache
            maxEntriesLocalHeap="10000"
            eternal = "false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
        <persistence strategy ="localTempSwap"/>
    </defaultCache>

    <!-- ShiroTest缓存 -->
    <cache name ="ShiroTestCache"
           maxEntriesLocalHeap="1000"
           eternal = "false"
           timeToIdleSeconds="5"
           timeToLiveSeconds="5"
           overflowToDisk="false"
           memoryStoreEvictionPolicy="LRU"/>
</ehcache>

4、在static下新建js文件夹,并将md5 js加密算法与 jquery复制到js下
在这里插入图片描述
5、template下添加login.html,noPermission.html,Index.html

                                      <!--login.html-->
<!DOCTYPE html>
<html lang="en" xmlns:th ="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script th:src="@{|/js/jquery-1.8.0.min.js|}"></script>
    <script th:src="@{|/js/jquery.md5.js|}"></script>
    <script>
        //页面加载完毕后将登录按钮单件事件绑定以下方法
        $(function(){
            $("#btnSubmit").bind("click",function() {
                var  md5_password = $.md5($("#password").val());
                console.log(md5_password);
                alert(md5_password);
                $("#md5Password").val(md5_password);
            })
        })
    </script>
</head>
<body>
<form action ="/" method="post">
    <label>用户名</label><input type = "text" id = "userName" name ="userName"><br>
    <label>密码</label><input type ="password" id = "password"><br>
    <input type ="hidden" id = "md5Password" name ="password">
    <input type = "submit" id ="btnSubmit" value ="登录">
    <span style="color:firebrick" th:text="${errMessage}"/>
</form>
</body>
</html>
                        <!--noPermission.html-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="color: firebrick">对不起,您没有操作权限</h1>
</body>
</html>
                    <!--index.html-->
<!DOCTYPE html>
<!--添加thymeleaf与shiro命名空间-->
<html lang="en" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro ="http://www.polix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<shiro:guest>
    您还没有登录
</shiro:guest>
<a th:href = "@{|/user/add|}">添加用户</a>
<a th:href = "@{|/user/update|}">修改用户</a>
<a th:href = "@{|/user/delete|}">删除用户</a>
<!--登录之后才可以查找用户-->
<shiro:authenticated>
    <a th:href = "@{|/user/search|}">查找用户</a>
</shiro:authenticated>
</body>
</html>
</body>
</html>

6、添加controller文件夹,并在其下添加TestController类

package com.example.shirotest.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*;

@Controller
public class TestController {
    @GetMapping("/index")
    public String index (){
        return "index";
    }
    @GetMapping("/")
    public String toLogin(){
        return "login";
    }
    @PostMapping("/")
    public String login(String userName, String password, Model model){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        /*如果用户没有通过认证,认证用户*/
        if(!subject.isAuthenticated()){
            //创建UsernamePasswordToke对象
            String errMessage;
            UsernamePasswordToken token = new UsernamePasswordToken(userName,password);
            try {
                subject.login(token);
            } catch (UnknownAccountException e) {
                errMessage = "用户名不存在";
                model.addAttribute("errMessage",errMessage);
                return "login";
            } catch (IncorrectCredentialsException e){
                errMessage = "密码不正确";
                model.addAttribute("errMessage",errMessage);
                return "login";
            } catch(LockedAccountException e){
                model.addAttribute("errMessage","您的账号已经被锁定");
                return "login";
            }
            catch (AuthenticationException e){
                model.addAttribute("errMessage","认证失败");
                return "login";
            }
        }

        return "redirect:index";

    }

    @RequiresPermissions(value ={"user:add"})
    @RequestMapping("/user/add")
    @ResponseBody
    public String userAdd(){
        return "userAdd";
    }

    @RequiresPermissions(value={"user:update"})
    @RequestMapping("/user/update")
    @ResponseBody
    public String userUpdate(){
        return "userUpdate";
    }

    @RequiresPermissions(value ={"user:delete"})
    @RequestMapping("/user/delete")
    @ResponseBody
    public String userDelete(){
        return "userDelete";
    }
    @RequestMapping("/user/search")
    @ResponseBody
    public String userSelect(){
        return "userSelect";
    }
    @RequestMapping("/noPermission")
    public String noPermission(){
        return "noPermission";
    }
    //通过@RequiresPermission标识的无权限异常在此处理
    @ExceptionHandler(value={AuthorizationException.class})
    public String permissionError(Throwable throwable){
        return "noPermission";
    }
}

7、添加自定义realm MyRealm继承自AuthorizingRealm

package com.example.shirotest.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;

import java.util.HashSet;
import java.util.Set;

public class MyRealm extends AuthorizingRealm {
    //授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        Object obj = principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        Set<String> roles = new HashSet<>();
        Set<String> permissions = new HashSet<>();
        //此处应该是根据用户名查询出所有角色与权限
        if(obj.equals("admin")){
            roles.add("admin");
            permissions.add("user:add");
            permissions.add("user:update");
            permissions.add("user:delete");
            permissions.add("user:search");
        }
        info.addRoles(roles);
        info.addStringPermissions(permissions);
        return info;
    }

    //认证账户
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //根据principalCollection参数获得authenticationToken
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        String userName = token.getUsername();
        String password = new String(token.getPassword());

        //此部分应该是查找数据库后根据是否存在用户及用户密码输错次数判断
        if(!"admin".equals(userName) && !"zhangsan".equals(userName) && !"user".equals(userName)){
            throw new UnknownAccountException();
        }else if("zhangsan".equals(userName)){
            throw new LockedAccountException();
        }
        /*
         *参数1:服务器或输入的用户名,参数2:服务器中的密码,参数3,当前rea的名字
         */
        return  new SimpleAuthenticationInfo(userName,"e10adc3949ba59abbe56e057f20f883e",getName());
    }
}

8、添加config文件夹,并添加ShiroConfig配置类

package com.example.shirotest.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.example.shirotest.realm.MyRealm;
import net.sf.ehcache.CacheManager;
import org.apache.shiro.cache.ehcache.EhCacheManager;
import org.apache.shiro.io.ResourceUtils;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.realm.Realm;
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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.io.IOException;
import java.io.InputStream;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    //生成MyRealm bean
    @Bean
    public MyRealm myRealm(){
        MyRealm myRealm = new MyRealm();
        return myRealm;
    }
    //生成EhCache bean
    @Bean
    public EhCacheManager ehCacheManager(){
        EhCacheManager ehCacheManager = new EhCacheManager();
        InputStream inputStream = null;
        try {
            inputStream = ResourceUtils.getInputStreamForPath("classpath:ehcache/ehcache.xml");
        } catch (IOException e) {
            e.printStackTrace();
        }
        CacheManager cacheManager = new CacheManager(inputStream);
        ehCacheManager.setCacheManager(cacheManager);
        return  ehCacheManager;
    }
    //生成SecurityManager bean
    @Bean
    public SecurityManager securityManager(MyRealm myRealm,EhCacheManager ehCacheManager){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(myRealm);
        //securityManager.setCacheManager(ehCacheManager);
        return securityManager;

    }
    //生成ShiroFilterFactoryBean bean
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        //创建ShiroFilterFactoryBean
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //设置SecurityManager对象
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //设置登录页面
        shiroFilterFactoryBean.setLoginUrl("/");
        //设置登录成功后跳转的页面
        shiroFilterFactoryBean.setSuccessUrl("/index");
        //设置没有权限跳转的页面
        shiroFilterFactoryBean.setUnauthorizedUrl("/noPermission");
        /*
         * 设置页面拦截规则
         */
        Map<String,String> filterChainMap = new LinkedHashMap<>();
        //配置登陆请求不需要认证 anon表示某个请求不需要认证
        filterChainMap.put("/","anon");
        filterChainMap.put("/noPermission","anon");
        //配置登出的请求,登出后会清空当前用户的内存
        filterChainMap.put("/logout","logout");
        //配置一个admin开头的所有请求需要登录 authc表示需要登录认证
        filterChainMap.put("/user/add","authc,roles[admin]");
        //配置一个user开头的所有请求需要登录 authc表示需要登录认证
        filterChainMap.put("/user/**","authc");
        filterChainMap.put("/js/**","anon");
        //配置剩余的所有请求全部需要进行登录认证(注意:这个必须写在最后面,否则其后的配置不管用),可选配置
        filterChainMap.put("/**","authc");
        //设置权限拦截规则
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainMap);
        return shiroFilterFactoryBean;
    }
    //开启shiro注解支持,不开启controller中的@RequiresPermissions无效
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }
    //开启AOP的支持,不开启controller中的@RequiresPermissions无效
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
    //配置shiro与thymeleaf的集成
    @Bean
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 您好,针对您的问题,我可以回答。 在shiro中,可以通过SessionManager的配置来实现踢出用户的操作。具体步骤如下: 1. 在shiro.ini或者shiro-config.xml中配置SessionManager,指定其使用的SessionDAO和SessionValidationScheduler。 2. 实现自定义的SessionDAO,其中需要实现doDelete方法,在该方法中删除指定用户的session。 3. 实现自定义的SessionValidationScheduler,其中需要实现相应的定时任务,用于定期验证session是否过期并清除过期的session。 4. 在需要踢出用户的地方,通过SessionDAO的delete方法删除该用户的session即可。 需要注意的是,在使用shiro进行用户管理时,建议不要直接操作Session对象,而是使用Subject对象提供的API进行操作。另外,在进行session管理时,需要注意session的超时时间设置,以避免session占用过多资源或者安全问题的出现。 ### 回答2: Shiro是一个强大的Java安全框架,提供了许多功能,包括会话(session)管理和用户踢出功能。 在Shiro中,会话管理是通过SessionManager实现的。SessionManager负责创建、管理和销毁会话,并提供了一些与会话相关的操作和功能。可以使用Shiro提供的默认的SessionManager实现,也可以根据自己的需求自定义SessionManager。 当需要踢出用户时,可以通过调用SessionManager的getSession方法获取指定用户的会话,并通过调用会话的stop方法来销毁会话。代码示例如下: ```java // 获取SessionManager实例 SessionManager sessionManager = SecurityUtils.getSecurityManager().getSessionManager(); // 获取指定用户的会话 Session session = sessionManager.getSession(new DefaultSessionKey(userId)); // 销毁会话 session.stop(); ``` 上述代码通过SecurityUtils.getSecurityManager()方法获取了Shiro的SecurityManager实例,然后通过SecurityManager获取SessionManager实例。接着使用getSession方法获取指定用户的会话,这里使用了DefaultSessionKey封装了用户id。最后,调用会话的stop方法来销毁会话。 需要注意的是,用户被踢出后,他将无法再通过该会话进行访问。如果用户再次发起请求,Shiro会自动为其创建一个新的会话。 通过Shiro的会话管理和用户踢出功能,我们可以更好地管理用户的会话,并确保安全性和控制访问权限。 ### 回答3: shiro是一个Java的安全框架,用于处理认证、授权和会话管理等安全相关的功能。在shiro中,可以通过session管理功能来踢出用户。 session是指在服务器端保存用户信息的机制,它可以用来跟踪用户的会话状态。shiro的session管理功能可以通过设置session超时时间来自动踢出用户,即当用户的会话超过设定的时间后,会自动使用户失效,需要重新登录。 要实现用户踢出功能,可以通过在登录时记录用户的session信息,并将其保存在某个集合中。当其他用户登录时,可以检查该集合中是否存在相同的session信息。如果存在,则说明该用户已经在其他地方登录,可以将其之前的session失效,实现踢出用户的效果。 具体实现可以参考以下步骤: 1. 在登录成功后,将用户的session信息记录下来,保存在某个集合中(比如使用ConcurrentHashMap来保存用户ID和session的映射关系); 2. 当其他用户登录时,检查集合中是否存在相同的session信息; 3. 如果存在相同的session信息,则将该用户之前的session设置为失效(通过shiro的SessionDao的delete方法删除之前的session信息); 4. 响应踢出用户的操作给前端页面,让用户重新登录。 需要注意的是,为了确保安全性,对于session信息的管理要进行适当的加密和验证,避免被恶意篡改或伪造。另外,定时清理集合中的过期session信息也是必要的,以免集合中的数据过多,影响系统性能。 通过shiro的session管理能够方便地实现用户踢出功能,提高系统的安全性和稳定性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值