在 springboot 中如何整合 shiro 应用 ?
Shiro是Apache下的一个开源项目,我们称之为Apache Shiro。
它是一个很易用与Java项目的的安全框架,提供了认证、授权、加密、会话管理,与spring Security 一样都是做一个权限的安全框架,但是与Spring Security 相比,在于 Shiro 使用了比较简单易懂易于使用的授权方式。
shiro属于轻量级框架,相对于security简单的多,也没有security那么复杂。
所以我这里也是简单介绍一下shiro的使用。
其基本功能点如下图所示:
Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限;
Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的;
Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
Web Support:Web支持,可以非常容易的集成到Web环境;
Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率;
Concurrency:shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;
Testing:提供测试支持;
Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。
记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。
这里我就简单介绍一下 springboot 和 shiro 整合与基本使用。
1)目录结构
2)需要的基础包:pom.xml
- <?xml version="1.0" encoding="UTF-8"?>
- <project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <groupId>com.troy</groupId>
- <artifactId>springshiro</artifactId>
- <version>1.0-SNAPSHOT</version>
- <parent>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-parent</artifactId>
- <version>1.5.6.RELEASE</version>
- </parent>
- <dependencies>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-web</artifactId>
- <version>1.5.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-data-jpa</artifactId>
- <version>1.5.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-autoconfigure</artifactId>
- <version>1.5.6.RELEASE</version>
- </dependency>
- <dependency>
- <groupId>mysql</groupId>
- <artifactId>mysql-connector-Java</artifactId>
- <version>5.1.9</version>
- </dependency>
- <dependency>
- <groupId>org.apache.shiro</groupId>
- <artifactId>shiro-spring</artifactId>
- <version>1.3.2</version>
- </dependency>
- <dependency>
- <groupId>com.alibaba</groupId>
- <artifactId>druid</artifactId>
- <version>1.1.4</version>
- </dependency>
- </dependencies>
- </project>
3)基本配置application.yml
- server:
- port: 8082
- spring:
- datasource:
- driver-class-name: com.mysql.jdbc.Driver
- url: jdbc:mysql://localhost:3306/spring_shiro?useUnicode=true&characterEncoding=UTF-8
- username: root
- password: root
- type: com.alibaba.druid.pool.DruidDataSource
- jpa:
- show-sql: true
- hibernate:
- ddl-auto: update
- http:
- encoding:
- charset: utf-8
- enabled: true
4)这里我们基本需要3个实体,用户,角色和权限
(1) 角色:User.class
- @Entity
- public class User {
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Long id;
- @Column(unique = true)
- private String name;
- private Integer password;
- @OneToMany(cascade = CascadeType.ALL,mappedBy = "user")
- private List<Role> roles;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public List<Role> getRoles() {
- return roles;
- }
- public void setRoles(List<Role> roles) {
- this.roles = roles;
- }
- public Integer getPassword() {
- return password;
- }
- public void setPassword(Integer password) {
- this.password = password;
- }
- }
注:这里我只考虑一个用户对多个角色,不考虑多对多的关系
(2)角色:Role.class
- @Entity
- public class Role {
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Long id;
- private String roleName;
- @ManyToOne(fetch = FetchType.EAGER)
- private User user;
- @OneToMany(cascade = CascadeType.ALL,mappedBy = "role")
- private List<Permission> permissions;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getRoleName() {
- return roleName;
- }
- public void setRoleName(String roleName) {
- this.roleName = roleName;
- }
- public User getUser() {
- return user;
- }
- public void setUser(User user) {
- this.user = user;
- }
- public List<Permission> getPermissions() {
- return permissions;
- }
- public void setPermissions(List<Permission> permissions) {
- this.permissions = permissions;
- }
- }
(3)权限:Permission.class
- @Entity
- public class Permission {
- @Id
- @GeneratedValue(strategy = GenerationType.AUTO)
- private Long id;
- private String permission;
- @ManyToOne(fetch = FetchType.EAGER)
- private Role role;
- public Long getId() {
- return id;
- }
- public void setId(Long id) {
- this.id = id;
- }
- public String getPermission() {
- return permission;
- }
- public void setPermission(String permission) {
- this.permission = permission;
- }
- public Role getRole() {
- return role;
- }
- public void setRole(Role role) {
- this.role = role;
- }
- }
5)然后就是配置对应的验证,以及过滤条件
(1) 验证,以及权限的添加MyShiroRealm.class
- //实现AuthorizingRealm接口用户用户认证
- public class MyShiroRealm extends AuthorizingRealm{
- //用于用户查询
- @Autowired
- private ILoginService loginService;
- //角色权限和对应权限添加
- @Override
- protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
- //获取登录用户名
- String name= (String) principalCollection.getPrimaryPrincipal();
- //查询用户名称
- User user = loginService.findByName(name);
- //添加角色和权限
- SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
- for (Role role:user.getRoles()) {
- //添加角色
- simpleAuthorizationInfo.addRole(role.getRoleName());
- for (Permission permission:role.getPermissions()) {
- //添加权限
- simpleAuthorizationInfo.addStringPermission(permission.getPermission());
- }
- }
- return simpleAuthorizationInfo;
- }
- //用户认证
- @Override
- protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
- //加这一步的目的是在Post请求的时候会先进认证,然后在到请求
- if (authenticationToken.getPrincipal() == null) {
- return null;
- }
- //获取用户信息
- String name = authenticationToken.getPrincipal().toString();
- User user = loginService.findByName(name);
- if (user == null) {
- //这里返回后会报出对应异常
- return null;
- } else {
- //这里验证authenticationToken和simpleAuthenticationInfo的信息
- SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(name, user.getPassword().toString(), getName());
- return simpleAuthenticationInfo;
- }
- }
- }
(2)过滤配置:ShiroConfiguration.class
- @Configuration
- public class ShiroConfiguration {
- //将自己的验证方式加入容器
- @Bean
- public MyShiroRealm myShiroRealm() {
- MyShiroRealm myShiroRealm = new MyShiroRealm();
- return myShiroRealm;
- }
- //权限管理,配置主要是Realm的管理认证
- @Bean
- public SecurityManager securityManager() {
- DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
- securityManager.setRealm(myShiroRealm());
- return securityManager;
- }
- //Filter工厂,设置对应的过滤条件和跳转条件
- @Bean
- public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
- ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
- shiroFilterFactoryBean.setSecurityManager(securityManager);
- Map<String,String> map = new HashMap<String, String>();
- //登出
- map.put("/logout","logout");
- //对所有用户认证
- map.put("/**","authc");
- //登录
- shiroFilterFactoryBean.setLoginUrl("/login");
- //首页
- shiroFilterFactoryBean.setSuccessUrl("/index");
- //错误页面,认证不通过跳转
- shiroFilterFactoryBean.setUnauthorizedUrl("/error");
- shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
- return shiroFilterFactoryBean;
- }
- //加入注解的使用,不加入这个注解不生效
- @Bean
- public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
- AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
- authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
- return authorizationAttributeSourceAdvisor;
- }
- }
6)接下来就是数据访问层、业务层、以及控制层
(1) 数据层:BaseRepository.class,UserRepository.class,RoleRepository.class
- @NoRepositoryBean
- public interface BaseRepository<T,I extends Serializable> extends PagingAndSortingRepository<T,I>,JpaSpecificationExecutor<T>{
- }
- public interface UserRepository extends BaseRepository<User,Long>{
- User findByName(String name);
- }
- public interface RoleRepository extends BaseRepository<Role,Long> {
- }
(2)业务层:LoginServiceImpl.class
- @Service
- @Transactional
- public class LoginServiceImpl implements ILoginService {
- @Autowired
- private UserRepository userRepository;
- @Autowired
- private RoleRepository roleRepository;
- //添加用户
- @Override
- public User addUser(Map<String, Object> map) {
- User user = new User();
- user.setName(map.get("username").toString());
- user.setPassword(Integer.valueOf(map.get("password").toString()));
- userRepository.save(user);
- return user;
- }
- //添加角色
- @Override
- public Role addRole(Map<String, Object> map) {
- User user = userRepository.findOne(Long.valueOf(map.get("userId").toString()));
- Role role = new Role();
- role.setRoleName(map.get("roleName").toString());
- role.setUser(user);
- Permission permission1 = new Permission();
- permission1.setPermission("create");
- permission1.setRole(role);
- Permission permission2 = new Permission();
- permission2.setPermission("update");
- permission2.setRole(role);
- List<Permission> permissions = new ArrayList<Permission>();
- permissions.add(permission1);
- permissions.add(permission2);
- role.setPermissions(permissions);
- roleRepository.save(role);
- return role;
- }
- //查询用户通过用户名
- @Override
- public User findByName(String name) {
- return userRepository.findByName(name);
- }
- }
(3)控制层:LoginResource.class
- @RestController
- public class LoginResource {
- @Autowired
- private ILoginService loginService;
- //退出的时候是get请求,主要是用于退出
- @RequestMapping(value = "/login",method = RequestMethod.GET)
- public String login(){
- return "login";
- }
- //post登录
- @RequestMapping(value = "/login",method = RequestMethod.POST)
- public String login(@RequestBody Map map){
- //添加用户认证信息
- Subject subject = SecurityUtils.getSubject();
- UsernamePasswordToken usernamePasswordToken = new UsernamePasswordToken(
- map.get("username").toString(),
- map.get("password").toString());
- //进行验证,这里可以捕获异常,然后返回对应信息
- subject.login(usernamePasswordToken);
- return "login";
- }
- @RequestMapping(value = "/index")
- public String index(){
- return "index";
- }
- //登出
- @RequestMapping(value = "/logout")
- public String logout(){
- return "logout";
- }
- //错误页面展示
- @RequestMapping(value = "/error",method = RequestMethod.POST)
- public String error(){
- return "error ok!";
- }
- //数据初始化
- @RequestMapping(value = "/addUser")
- public String addUser(@RequestBody Map<String,Object> map){
- User user = loginService.addUser(map);
- return "addUser is ok! \n" + user;
- }
- //角色初始化
- @RequestMapping(value = "/addRole")
- public String addRole(@RequestBody Map<String,Object> map){
- Role role = loginService.addRole(map);
- return "addRole is ok! \n" + role;
- }
- //注解的使用
- @RequiresRoles("admin")
- @RequiresPermissions("create")
- @RequestMapping(value = "/create")
- public String create(){
- return "Create success!";
- }
- }
注:这里对于注解的使用,在最后一个很重要!
7)shiro的使用基本上就是这样子了,主要是权限的控制,其他的主要是做跳转和切换使用
8)最后配上数据库信息:结合控制层观看
user:
role:
permission:
在 springboot 中如何整合 shiro 应用 ?的更多相关文章
- SpringBoot 优雅的整合 Shiro
Apache Shiro是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理.借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序 - 从最小的移动应用程序到最 ...
- redis(Springboot中封装整合redis,java程序如何操作redis的5种基本数据类型)
平常测试redis操作命令,可能用的是cmd窗口 操作redis,记录一下 java程序操作reids, 操作redis的方法 可以用Jedis ,在springboot 提供了两种 方法操作 Red ...
- SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)在pom.xml中添加依赖: <properties> <shi ...
- SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cooki ...
- SpringBoot学习:整合shiro(rememberMe记住我后自动登录session失效解决办法)
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 定义一个拦截器,判断用户是通过记住我登录时,查询数据库后台自动登录,同时把用户放入ses ...
- SpringBoot学习:整合shiro(验证码功能和登录次数限制功能)
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)验证码 首先login.jsp里增加了获取验证码图片的标签: <body s ...
- SpringBoot学习:整合shiro(rememberMe记住我功能)
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; ...
- 关于Springboot中dubbo整合注意的误区(不对之处请指出)
这是我的客户端配置! 这是生产的配置, 首先注意一下 scan 我之前尝试这样的客户端配置 然后 果断客户端不能注册接口 @Reference(version="1.0") ...
- SpringBoot 中aop整合方法执行日志
今天事情不多, 处理完手中的事边想着捣鼓一下AOP, 着手开始写才发现, 多久不用, 自己已经忘得差不多了, 捣鼓半天之后, 慢慢整出这个小demo,以便于以后查阅回顾 1 .先创建一个注解, 用来作 ...
随机推荐
- 学习笔记20151211——AXI4 STREAM DATA FIFO
AXI4 STREAM DATA FIFO是输入输出接口均为AXIS接口的数据缓存器,和其他fifo一样是先进先出形式.可以在跨时钟域的应用中用于数据缓冲,避免亚稳态出现.支持数据的分割和数据拼接.在 ...
- CASIO 5800P计算器游戏--猜数字游戏
CASIO 5800P 计算器游戏--猜数字游戏原代码 我编的计算器小游戏--猜数字游戏 LbI I↙ "xxGUESS NUMBERxx xPROGRAMMER:JCHx -------- ...
- 建造者模式 build
引出建造者模式: package com.disign.build; /** * Created by zhen on 2017-05-19. */ public class BuildPersonT ...
- MVC项目使用Oracle数据库运行提示:找不到请求的 .Net Framework Data Provider。可能没有安装
MVC项目使用Entity Framework针对Oracle数据库进行开发时,由于Oracle官方网站一般建议开发者在64位操作系统中使用32位ODP.Net进行开发.在进行程序编码的时候不会有问题 ...
- 通过VNC连接远程服务器,然后登陆服务器上的虚拟机,出现键盘输入问题的解决方法
前几天由于要在服务器上装一个虚拟机,然后就选择了vmware workstation,装好之后,进入虚拟机中的centOS系统,发现键盘上的Cpas Lock键不起作用,按下之后还是输入小写,而且按住 ...
- Sqlserver 按照时间段统计数据
WITH t1 ( [hour], title ) , ' 0:00:00--- 1:00:00' UNION ALL , ' 1:00:00--- 2:00:00' UNION ALL , ' 2: ...
- Django 之 Ajax
此次主要是做省市区的三级联动. 环境:django 1.10 1. urls.py # coding:utf-8 from django.conf.urls import url import vie ...
- Linux udhcp client (udhcpc) get IP at anytime
/*************************************************************************************** * Linux udh ...
- Convex 一道阿姆斯特朗回旋好题
2001年5月8日,阿姆斯特朗(Armstrong, 1929-2013) 教授发明了一种名为“阿姆斯特朗回旋加速喷气式阿姆斯特朗加密”的加密算法,算法从未公开,直至2013阿姆斯特朗教授逝世后,其生 ...
- 使用ajax提交form表单,包括ajax文件上传 转http://www.cnblogs.com/zhuxiaojie/p/4783939.html
使用ajax提交form表单,包括ajax文件上传 前言 使用ajax请求数据,很多人都会,比如说: $.post(path,{data:data},function(data){ ... },&qu ...