1、shiro的三个核心概念:
  1)Subject:代表当前正在执行操作的用户,但Subject代表的可以是人,也可以是任何第三方系统帐号。当然每个subject实例都会被绑定到SercurityManger上。
  2)SecurityManger:SecurityManager是Shiro核心,主要协调Shiro内部的各种安全组件,这个我们不需要太关注,只需要知道可以设置自定的Realm。
  3)Realm:用户数据和Shiro数据交互的桥梁。比如需要用户身份认证、权限认证。都是需要通过Realm来读取数据。

2、springboot中集成shiro相对简单,只需要两个类:一个是ShiroConfig类,一个是自定义Realm类。

  1)ShiroConfig类:shiro的一些配置,相对于之前的xml配置。包括:ShiroFilter的配置,密码加密的算法,支持注解的配置等功能。

  2)自定义Realm类:继承AuthorizingRealm。并且重写父类中的doGetAuthorizationInfo(权限认证)、doGetAuthenticationInfo(身份认证)这两个方法。

3、demo

  项目结构:

  

  依赖:

<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>

  ShiroConfig

package com.oy;

import java.util.LinkedHashMap;
import java.util.Map; 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.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn; /**
* @author oy
* @date 2019年8月10日 下午4:50:55
* @version 1.0.0
*/
@Configuration
public class ShiroConfig { /************************* shiroFilter配置 start *************************/
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager); shiroFilterFactoryBean.setLoginUrl("/login");
shiroFilterFactoryBean.setUnauthorizedUrl("/unauth"); Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
// authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问
filterChainDefinitionMap.put("/webjars/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/user/login", "anon");
filterChainDefinitionMap.put("/", "anon");
filterChainDefinitionMap.put("/front/**", "anon");
filterChainDefinitionMap.put("/api/**", "anon"); filterChainDefinitionMap.put("/admin/**", "authc");
filterChainDefinitionMap.put("/user/**", "authc"); // 剩余的都需要认证
// 这行代码必须放在所有权限设置的最后,不然会导致所有url都被拦截
filterChainDefinitionMap.put("/**", "authc");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
} @Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager defaultSecurityManager = new DefaultWebSecurityManager();
defaultSecurityManager.setRealm(myRealm());
return defaultSecurityManager;
} @Bean
public MyRealm myRealm() {
MyRealm myRealm = new MyRealm();
return myRealm;
}
/************************* shiroFilter配置 end *************************/ /************************* 开启shiro注解配置 start *************************/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} /**
* 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),
* 需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证.
* 配置以下两个bean(DefaultAdvisorAutoProxyCreator(可选)和AuthorizationAttributeSourceAdvisor)即可实现此功能
*/
@Bean
@DependsOn({ "lifecycleBeanPostProcessor" })
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
} @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
/************************* 开启shiro注解配置 end *************************/
}

  MyRealm

package com.oy;

import java.util.HashSet;
import java.util.Set; import javax.annotation.Resource; import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
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 com.oy.model.User;
import com.oy.service.UserService; public class MyRealm extends AuthorizingRealm { @Resource
private UserService userService; /**
* 认证:身份认证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
String username = (String) token.getPrincipal();
User user = userService.getUserByUsername(username);
if (user != null) {
AuthenticationInfo authcInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), getName());
return authcInfo;
} else {
return null;
}
} /**
* 授权:权限认证
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//String userName = (String) principals.getPrimaryPrincipal();
//authorizationInfo.setRoles(userService.getRoles(userName));
//authorizationInfo.setStringPermissions(userService.getPermissions(userName)); Set<String> stringSet = new HashSet<>();
stringSet.add("user:view");
stringSet.add("user:edit");
authorizationInfo.setStringPermissions(stringSet);
return authorizationInfo;
}
}

  

  IndexController

package com.oy.controller;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody; import com.oy.util.CryptographyUtil; /**
* @author oy
* @date 2019年8月10日 下午6:21:58
* @version 1.0.0
*/
@Controller
public class IndexController { @RequestMapping("/login")
public String login() {
return "login.html";
} @RequestMapping("/user/login")
@ResponseBody
public String doLogin(@RequestParam(value = "username", required = false) String username,
@RequestParam(value = "password", required = false) String password) { System.out.println("username=" + username + ", password=" + password);
// 从SecurityUtils里边创建一个 subject
Subject subject = SecurityUtils.getSubject();
// 在认证提交前准备 token(令牌)
//UsernamePasswordToken token = new UsernamePasswordToken(username, password);
UsernamePasswordToken token = new UsernamePasswordToken(username, CryptographyUtil.md5(password, "abc123"));
// 执行认证登陆
try {
subject.login(token);
} catch (UnknownAccountException uae) {
return "未知账户";
} catch (IncorrectCredentialsException ice) {
return "密码不正确";
} catch (LockedAccountException lae) {
return "账户已锁定";
} catch (ExcessiveAttemptsException eae) {
return "用户名或密码错误次数过多";
} catch (AuthenticationException ae) {
return "用户名或密码不正确!";
} if (subject.isAuthenticated()) {
return "登录成功";
} else {
token.clear();
return "登录失败";
}
} @RequiresPermissions("user:view")
@GetMapping("/user")
@ResponseBody
public String userList() {
return "user list";
} @RequiresPermissions("book:view")
@GetMapping("/book")
@ResponseBody
public String bookList() {
return "book list";
} @RequestMapping("/unauth")
public String unauth() {
return "unauth.html";
}
}

  login.html

<body>
<h2>login页面</h2>
<form action="/user/login" method="post">
username: <input type="text" name="username" value=""/></br></br>
password: <input type="text" name="password" value=""/></br>
<input type="submit" value="submit"/>
</form>
</body>

  CryptographyUtil

package com.oy.util;

import org.apache.shiro.codec.Base64;
import org.apache.shiro.crypto.hash.Md5Hash; public class CryptographyUtil { /**
* base64加密
* @param str
* @return
*/
public static String encBase64(String str) {
return Base64.encodeToString(str.getBytes());
} /**
* base64解密
* @param str
* @return
*/
public static String decBase64(String str) {
return Base64.decodeToString(str);
} /**
* Md5加密
* @param str
* @param salt
* @return
*/
public static String md5(String str, String salt) {
return new Md5Hash(str, salt).toString();
} public static void main(String[] args) {
String password = "123456";
System.out.println("Base64加密:" + CryptographyUtil.encBase64(password));
System.out.println("Base64解密:" + CryptographyUtil.decBase64(CryptographyUtil.encBase64(password))); // a6f70dedd698be90addd35abe38d3876
System.out.println("Md5加密:" + CryptographyUtil.md5(password, "abc123"));
}
}

 参考资料:

  1)SpringBoot2.0集成Shiro

  2)SpringBoot搭建基于Apache Shiro的权限管理功能

  3)shiro无权限,不跳转到指定页面。setUnauthorizedUrl无效

  4)setUnauthorizedUrl("/403")不起作用,不能设置没有权限的跳转页面

  5)shiro的@RequiresPermissions不生效和无权限跳异常而不是shiro指定的无权页面

SpringBoot2.0集成Shiro的更多相关文章

  1. (补漏)Springboot2.0 集成shiro权限管理

    原文Springboot2.0 集成shiro权限管理 一.关于停止使用外键. 原本集成shiro建立用户.角色.权限表的时候使用了外键,系统自动创建其中两个关联表,用@JoinTable.看起来省事 ...

  2. springboot2.0集成shiro出现ShiroDialect报错找不到AbstractTextChildModifierAttrPr

    @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } 报错出现找不到org/thymeleaf/process ...

  3. Springboot2.0 集成shiro权限管理

    在springboot中结合shiro教程搭建权限管理,其中几个小细节的地方对新手不友好,伸手党更是无法直接运行代码,搭建过程容易遇坑,记录一下.关键的地方也给注释了. 版本:springboot版本 ...

  4. SpringBoot2.0集成FastDFS

    SpringBoot2.0集成FastDFS 前两篇整体上介绍了通过 Nginx 和 FastDFS 的整合来实现文件服务器.但是,在实际开发中对图片或文件的操作都是通过应用程序来完成的,因此,本篇将 ...

  5. springBoot2.0 配置shiro实现权限管理

    一.前言 基于上一篇springBoot2.0 配置 mybatis+mybatisPlus+redis 这一篇加入shiro实现权限管理 二.shiro介绍 2.1 功能特点 Shiro 包含 10 ...

  6. SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全 ...

  7. spring boot 2.0 集成 shiro 和 pac4j cas单点登录

    新开的项目,果断使用  spring boot  最新版本  2.0.3 ,免得后期升级坑太多,前期把雷先排了. 由于对 shiro 比较熟,故使用 shiro 来做权限控制.同时已经存在了 cas  ...

  8. springboot2.0整合shiro出现ShiroDialect报错 找不到org/thymeleaf/processor/attr/AbstractTextChildModifierAttrPr

    包版本过低,找最新包 https://mvnrepository.com/ <dependency> <groupId>com.github.theborakompanioni ...

  9. springboot2.0 集成elasticsearch,实现检索、分页、排序

    springboot整合es的方式: transport方式(7.0弃用,8.0移除) spring-data(完全当做数据库来用,无法全部支持es,内部也是基于transport,包装后使用非常简单 ...

随机推荐

  1. 第四周课程总结&实验报告(二)

    Java实验报告(二) 实验二 Java简单类与对象 一. 实验目的 (1) 掌握类的定义,熟悉属性.构造函数.方法的作用,掌握用类作为类型声明变量和方法返回值: (2) 理解类和对象的区别,掌握构造 ...

  2. 纯前端表格控件SpreadJS V12.1 隆重登场,专注易用性,提升用户体验

    ​ 一款优秀的开发工具,在更新迭代中,除了要满足不同场景的业务需求,也需不断优化已有功能,尤其是细节方面,要能为用户带来使用体验和开发效率的提升. 作为一款备受业界专家和开发者认可的纯前端类Excel ...

  3. 小记---------sparkRDD的Transformation 和 Action 及案例 原理解释

    RDD :弹性分布式数据集:是一个容错的.并行的数据结构,可以让用户显式地将数据存储到磁盘或内存中,并控制数据的分区   RDD是Spark的核心数据结构,通过RDD的依赖关系形成Spark的调度顺序 ...

  4. sublime text3 注册码 (Version 3.0)

    -– BEGIN LICENSE -– TwitterInc 200 User License EA7E-890007 1D77F72E 390CDD93 4DCBA022 FAF60790 61AA ...

  5. (四)Java秒杀项目之JMeter压测

    一.JMeter入门压测 1.打开JMeter工具,选中测试计划->右键添加->线程(用户)->线程组,页面中的线程数就是并发数,页面中的Ramp-Up时间(秒)表示通过多长时间启动 ...

  6. JAVA基础--JAVA API集合框架(其他集合类,集合原理)

    一.ArrayList介绍 1.ArrayList介绍 ArrayList它是List接口的真正的实现类.也是我们开发中真正需要使用集合容器对象. ArrayList类,它是List接口的实现.肯定拥 ...

  7. AcWing175电路维修

    这是一道在luogu的蓝题,在yxc大佬的讲解下AC掉了(百般调试) 首先这道题给了一个字符串矩阵,/ \表示相连哪两个节点,只可以走/ \所连接的两个点,但我们可以旋转每一个边,询问从1,1 走到 ...

  8. liunx 安装rsync

    新建一个rsync.s文件,把下面的代码写入文件里: #!/usr/bin/env bash mkdir -p /data/app/rsync/etc/ mkdir -p /data/logs/rsy ...

  9. 使用Python基于百度等OCR API的文字识别

    百度OCR Baidu OCR API:一定额度免费,目前是每日500次 Python SDK文档:https://cloud.baidu.com/doc/OCR/OCR-Python-SDK.htm ...

  10. mybatis插入出现org.apache.ibatis.executor.ExecutorException: No setter found for the keyProperty 'xxx'异常的原因

    确定有setter方法,问题其实是xml文件中,insert的主键的列名写错了,如下,一开始写成ComId <insert id="insertCom" parameterT ...