<h1>
<span class="link_title"><a href="/q975583865/article/details/78232811">
springboot(十四):springboot整合shiro-登录认证和权限管理 </a>
</span> </h1>
<div class="article_manage clearfix">

</div>    <style type="text/css">
.embody{
padding:10px 10px 10px;
margin:0 -20px;
border-bottom:solid 1px #ededed;
}
.embody_b{
margin:0 ;
padding:10px 0;
}
.embody .embody_t,.embody .embody_c{
display: inline-block;
margin-right:10px;
}
.embody_t{
font-size: 12px;
color:#999;
}
.embody_c{
font-size: 12px;
}
.embody_c img,.embody_c em{
display: inline-block;
vertical-align: middle;
}
.embody_c img{
width:30px;
height:30px;
}
.embody_c em{
margin: 0 20px 0 10px;
color:#333;
font-style: normal;
}
</style>
<script type="text/javascript">
$(function () {
try
{
var lib = eval("("+$("#lib").attr("value")+")");
var html = "";
if (lib.err == 0) {
$.each(lib.data, function (i) {
var obj = lib.data[i];
//html += '<img src="' + obj.logo + '"/>' + obj.name + "&nbsp;&nbsp;";
html += ' <a href="' + obj.url + '" target="_blank">';
html += ' <img src="' + obj.logo + '">';
html += ' <em><b>' + obj.name + '</b></em>';
html += ' </a>';
});
if (html != "") {
setTimeout(function () {
$("#lib").html(html);
$("#embody").show();
}, 100);
}
}
} catch (err)
{ } });
</script>

这篇文章我们来学习如何使用Spring Boot集成Apache Shiro。安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求。在Java领域一般有Spring Security、Apache Shiro等安全框架,但是由于Spring Security过于庞大和复杂,大多数公司会选择Apache Shiro来使用,这篇文章会先介绍一下Apache Shiro,在结合Spring Boot给出使用案例。

Apache Shiro

What is Apache Shiro?

Apache Shiro是一个功能强大、灵活的,开源的安全框架。它可以干净利落地处理身份验证、授权、企业会话管理和加密。

Apache Shiro的首要目标是易于使用和理解。安全通常很复杂,甚至让人感到很痛苦,但是Shiro却不是这样子的。一个好的安全框架应该屏蔽复杂性,向外暴露简单、直观的API,来简化开发人员实现应用程序安全所花费的时间和精力。

Shiro能做什么呢?

  • 验证用户身份
  • 用户访问权限控制,比如:1、判断用户是否分配了一定的安全角色。2、判断用户是否被授予完成某个操作的权限
  • 在非 web 或 EJB 容器的环境下可以任意使用Session API
  • 可以响应认证、访问控制,或者 Session 生命周期中发生的事件
  • 可将一个或以上用户安全数据源数据组合成一个复合的用户 "view"(视图)
  • 支持单点登录(SSO)功能
  • 支持提供“Remember Me”服务,获取用户关联信息而无需登录

等等——都集成到一个有凝聚力的易于使用的API。

Shiro 致力在所有应用环境下实现上述功能,小到命令行应用程序,大到企业应用中,而且不需要借助第三方框架、容器、应用服务器等。当然 Shiro 的目的是尽量的融入到这样的应用环境中去,但也可以在它们之外的任何环境下开箱即用。

Apache Shiro Features 特性

Apache Shiro是一个全面的、蕴含丰富功能的安全框架。下图为描述Shiro功能的框架图:

Authentication(认证), Authorization(授权), Session Management(会话管理), Cryptography(加密)被 Shiro 框架的开发团队称之为应用安全的四大基石。那么就让我们来看看它们吧:

  • Authentication(认证):用户身份识别,通常被称为用户“登录”
  • Authorization(授权):访问控制。比如某个用户是否具有某个操作的使用权限。
  • Session Management(会话管理):特定于用户的会话管理,甚至在非web 或 EJB 应用程序。
  • Cryptography(加密):在对数据源使用加密算法加密的同时,保证易于使用。

还有其他的功能来支持和加强这些不同应用环境下安全领域的关注点。特别是对以下的功能支持:

  • Web支持:Shiro 提供的 web 支持 api ,可以很轻松的保护 web 应用程序的安全。
  • 缓存:缓存是 Apache Shiro 保证安全操作快速、高效的重要手段。
  • 并发:Apache Shiro 支持多线程应用程序的并发特性。
  • 测试:支持单元测试和集成测试,确保代码和预想的一样安全。
  • "Run As":这个功能允许用户假设另一个用户的身份(在许可的前提下)。
  • "Remember Me":跨 session 记录用户的身份,只有在强制需要时才需要登录。

注意: Shiro不会去维护用户、维护权限,这些需要我们自己去设计/提供,然后通过相应的接口注入给Shiro

High-Level Overview 高级概述

在概念层,Shiro 架构包含三个主要的理念:Subject,SecurityManager和 Realm。下面的图展示了这些组件如何相互作用,我们将在下面依次对其进行描述。

  • Subject:当前用户,Subject 可以是一个人,但也可以是第三方服务、守护进程帐户、时钟守护任务或者其它--当前和软件交互的任何事件。
  • SecurityManager:管理所有Subject,SecurityManager 是 Shiro 架构的核心,配合内部安全组件共同组成安全伞。
  • Realms:用于进行权限信息的验证,我们自己实现。Realm 本质上是一个特定的安全 DAO:它封装与数据源连接的细节,得到Shiro 所需的相关的数据。在配置 Shiro 的时候,你必须指定至少一个Realm 来实现认证(authentication)和/或授权(authorization)。

我们需要实现Realms的Authentication 和 Authorization。其中 Authentication 是用来验证用户身份,Authorization 是授权访问控制,用于对用户进行的操作授权,证明该用户是否允许进行当前操作,如访问某个链接,某个资源文件等。

快速上手

基础信息

pom包依赖

<dependencies>
<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-data-jpa</artifactId>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-thymeleaf</artifactId>

</dependency>

<dependency>

<groupId>net.sourceforge.nekohtml</groupId>

<artifactId>nekohtml</artifactId>

<version>1.9.22</version>

</dependency>

<dependency>

<groupId>org.springframework.boot</groupId>

<artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

<groupId>org.apache.shiro</groupId>

<artifactId>shiro-spring</artifactId>

<version>1.4.0</version>

</dependency>
<dependency>
<groupId>mysql</groupId>

<artifactId>mysql-connector-java</artifactId>

<scope>runtime</scope>

</dependency>

</dependencies>

重点是 shiro-spring包

配置文件

spring:
datasource:

url: jdbc:mysql://localhost:3306/test

username: root

password: root

driver-class-name: com.mysql.jdbc.Driver

jpa:</br>
database: mysql</br>
show-sql: true</br>
hibernate:</br>
ddl-auto: update</br>
naming:</br>
strategy: org.hibernate.cfg.DefaultComponentSafeNamingStrategy</br>
properties:</br>
hibernate:</br>
dialect: org.hibernate.dialect.MySQL5Dialect</br></br> thymeleaf:</br>
cache: false</br>
mode: LEGACYHTML5</code></pre>

thymeleaf的配置是为了去掉html的校验

页面

我们新建了六个页面用来测试:

  • index.html :首页
  • login.html :登录页
  • userInfo.html : 用户信息页面
  • userInfoAdd.html :添加用户页面
  • userInfoDel.html :删除用户页面
  • 403.html : 没有权限的页面

除过登录页面其它都很简单,大概如下:

<!DOCTYPE html>

<html lang="en">

<head>
<meta charset="UTF-8">

<title>Title</title>

</head>

<body>

<h1>index</h1>

</body>

</html>

RBAC

RBAC 是基于角色的访问控制(Role-Based Access Control )在 RBAC 中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。

采用jpa技术来自动生成基础表格,对应的entity如下:

用户信息

@Entity

public class UserInfo implements Serializable {
@Id

@GeneratedValue

private Integer uid;
@Column(unique =true)
private String username;//帐号

private String name;//名称(昵称或者真实姓名,不同系统不同定义)

private String password; //密码;

private String salt;//加密密码的盐

private byte state;//用户状态,0:创建未认证(比如没有激活,没有输入验证码等等)--等待验证的用户 , 1:正常状态,2:用户被锁定.

@ManyToMany(fetch= FetchType.EAGER)//立即从数据库中进行加载数据;

@JoinTable(name = "SysUserRole", joinColumns = { @JoinColumn(name = "uid") }, inverseJoinColumns ={@JoinColumn(name = "roleId") })

private List<SysRole> roleList;// 一个用户具有多个角色
<span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">// 省略 get set 方法</span></span>

}

角色信息

@Entity
public class SysRole {

@Id@GeneratedValue

private Integer id; // 编号

private String role; // 角色标识程序中判断使用,如"admin",这个是唯一的:

private String description; // 角色描述,UI界面显示使用

private Boolean available = Boolean.FALSE; // 是否可用,如果不可用将不会添加给用户

<span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">//角色 -- 权限关系:多对多关系;</span></span></br>
<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@ManyToMany</span></span>(fetch= FetchType.<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">EAGER</span>)
<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinTable</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"SysRolePermission"</span></span>,joinColumns={<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinColumn</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"roleId"</span></span>)},inverseJoinColumns={<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinColumn</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"permissionId"</span></span>)})</br>
<span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">private</span></span> List&lt;SysPermission&gt; permissions;</br></br> <span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">// 用户 - 角色关系定义;</span></span></br>
<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@ManyToMany</span></span></br>
<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinTable</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"SysUserRole"</span></span>,joinColumns={<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinColumn</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"roleId"</span></span>)},inverseJoinColumns={<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@JoinColumn</span></span>(name=<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"uid"</span></span>)})</br>
<span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">private</span></span> List&lt;UserInfo&gt; userInfos;<span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">// 一个角色对应多个用户</span></span></br></br> <span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">// 省略 get set 方法</span></span></br>

}

权限信息

@Entity

public class SysPermission implements Serializable {

@Id@GeneratedValue
private Integer id;//主键.

private String name;//名称.

@Column(columnDefinition="enum('menu','button')")

private String resourceType;//资源类型,[menu|button]

private String url;//资源路径.

private String permission; //权限字符串,menu例子:role:*,button例子:role:create,role:update,role:delete,role:view

private Long parentId; //父编号

private String parentIds; //父编号列表

private Boolean available = Boolean.FALSE;
@ManyToMany

@JoinTable(name="SysRolePermission",joinColumns={@JoinColumn(name="permissionId")},inverseJoinColumns={@JoinColumn(name="roleId")})

private List<SysRole> roles;

<span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">// 省略 get set 方法</span></span></br>

}

根据以上的代码会自动生成user_info(用户信息表)、sys_role(角色表)、sys_permission(权限表)、sys_user_role(用户角色表)、sys_role_permission(角色权限表)这五张表,为了方便测试我们给这五张表插入一些初始化数据:

INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (1,0,'用户管理',0,'0/','userInfo:view','menu','userInfo/userList');

INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (2,0,'用户添加',1,'0/1','userInfo:add','button','userInfo/userAdd');

INSERT INTO `sys_permission` (`id`,`available`,`name`,`parent_id`,`parent_ids`,`permission`,`resource_type`,`url`) VALUES (3,0,'用户删除',1,'0/1','userInfo:del','button','userInfo/userDel');

INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (1,'0','管理员','admin');

INSERT INTO `sys_role` (`id`,`available`,`description`,`role`) VALUES (2,'0','VIP会员','vip');INSERT INTO `sys_role_permission` VALUES ('1', '1');

INSERT INTO `sys_role_permission` (`permission_id`,`role_id`) VALUES (1,1);

INSERT INTO color:rgb(163,21,21)">`sys_role_permission` (`permission_id`,`role_id`) VALUES (1,2);

INSERT INTO color:rgb(163,21,21)">`sys_role_permission` (`permission_id`,`role_id`) VALUES (1,3);

INSERT INTO `sys_user_role` (`role_id`,`uid`) VALUES (1,1);

INSERT INTO `user_info` (`uid`,`username`,`name`,`password`,`salt`,`state`) VALUES ('1', 'admin', '管理员', 'd3c59d25033dbf980d29554025c23a75', '8d78869f470951332959580424d4bf4f', 0);

Shiro 配置

首先要配置的是ShiroConfig类,Apache Shiro 核心通过 Filter 来实现,就好像SpringMvc 通过DispachServlet 来主控制一样。

既然是使用 Filter 一般也就能猜到,是通过URL规则来进行过滤和权限校验,所以我们需要定义一系列关于URL的规则和访问权限。

ShiroConfig

@Configuration

public class ShiroConfig {

@Bean

public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {

System.out.println("ShiroConfiguration.shirFilter()");

ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);

//拦截器.

Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();

// 配置不会被拦截的链接 顺序判断

filterChainDefinitionMap.put("/static/**", "anon");
//配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了

filterChainDefinitionMap.put("/logout", "logout");
//<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了;

//<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问-->

filterChainDefinitionMap.put("/**", "authc");
// 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面

shiroFilterFactoryBean.setLoginUrl("/login");
// 登录成功后要跳转的链接

shiroFilterFactoryBean.setSuccessUrl("/index");

    <span class="co" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-comment" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:green">//未授权界面;</span></span></br>
shiroFilterFactoryBean.<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">setUnauthorizedUrl</span>(<span class="st" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-string" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">"/403"</span></span>);
shiroFilterFactoryBean.<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">setFilterChainDefinitionMap</span>(filterChainDefinitionMap);
<span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">return</span></span> shiroFilterFactoryBean;</br>
}</br>





@Bean


public MyShiroRealm myShiroRealm(){


MyShiroRealm myShiroRealm = new MyShiroRealm();

return myShiroRealm;


}


<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-meta" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(43,145,175)">@Bean</span></span></br>
<span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-function" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">public</span></span></span><span class="hljs-function" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"> SecurityManager </span><span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-function" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-title" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(163,21,21)">securityManager</span></span></span><span class="hljs-function" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">()</span>{</br>
DefaultWebSecurityManager securityManager = <span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">new</span></span> <span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">DefaultWebSecurityManager</span>();
securityManager.<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">setRealm</span>(<span class="fu" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px">myShiroRealm</span>());</br>
<span class="kw" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px"><span class="hljs-keyword" style="font-size:undefined; line-height:inherit; margin:0px; padding:0px; border-style:solid; border-width:0px; color:rgb(0,0,255)">return</span></span> securityManager;</br>
}</br>

}

Filter Chain定义说明:

  • 1、一个URL可以配置多个Filter,使用逗号分隔
  • 2、当设置多个过滤器时,全部验证通过,才视为通过
  • 3、部分过滤器可指定参数,如perms,roles

Shiro内置的FilterChain

Filter Name Class
anon org.apache.shiro.web.filter.authc.AnonymousFilter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
port org.apache.shiro.web.filter.authz.PortFilter
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
ssl org.apache.shiro.web.filter.authz.SslFilter
user org.apache.shiro.web.filter.authc.UserFilter
  • anon:所有url都都可以匿名访问
  • authc: 需要认证才能进行访问
  • user:配置记住我或认证通过可以访问

登录认证实现

在认证、授权内部实现机制中都有提到,最终处理都将交给Real进行处理。因为在Shiro中,最终是通过Realm来获取应用程序中的用户、角色及权限信息的。通常情况下,在Realm中会直接从我们的数据源中获取Shiro需要的验证信息。可以说,Realm是专用于安全框架的DAO.

Shiro的认证过程最终会交由Realm执行,这时会调用Realm的getAuthenticationInfo(token)方法。

该方法主要执行以下操作:

  • 1、检查提交的进行认证的令牌信息
  • 2、根据令牌信息从数据源(通常为数据库)中获取用户信息
  • 3、对用户信息进行匹配验证。
  • 4、验证通过将返回一个封装了用户信息的AuthenticationInfo实例。
  • 5、验证失败则抛出AuthenticationException异常信息。

而在我们的应用程序中要做的就是自定义一个Realm类,继承AuthorizingRealm抽象类,重载doGetAuthenticationInfo(),重写获取用户信息的方法。

doGetAuthenticationInfo的重写


@Override

protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)

throws AuthenticationException {

System.out.println("MyShiroRealm.doGetAuthenticationInfo()");

//获取用户的输入的账号.

String username = (String)token.getPrincipal();

System.out.println(token.getCredentials());

//通过username从数据库中查找 User对象,如果找到,没找到.

//实际项目中,这里可以根据实际情况做缓存,如果不做,Shiro自己也是有时间间隔机制,2分钟内不会重复执行该方法

UserInfo userInfo = userInfoService.findByUsername(username);

System.out.println("----->>userInfo="+userInfo);

if(userInfo == null){

return null;


}

SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, //用户名

userInfo.getPassword(), //密码

ByteSource.Util.bytes(userInfo.getCredentialsSalt()),//salt=username+salt
getName() //realm name


);

return authenticationInfo;

}

链接权限的实现

shiro的权限授权是通过继承AuthorizingRealm抽象类,重载doGetAuthorizationInfo();当访问到页面的时候,链接配置了相应的权限或者shiro标签才会执行此方法否则不会执行,所以如果只是简单的身份认证没有权限的控制的话,那么这个方法可以不进行实现,直接返回null即可。在这个方法中主要是使用类:SimpleAuthorizationInfo进行角色的添加和权限的添加。

@Override

protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {

System.out.println("权限配置-->MyShiroRealm.doGetAuthorizationInfo()");

SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();

UserInfo userInfo = (UserInfo)principals.getPrimaryPrincipal();

for(SysRole role:userInfo.getRoleList()){

authorizationInfo.addRole(role.getRole());

for(SysPermission p:role.getPermissions()){
authorizationInfo.addStringPermission(p.getPermission());

}

}

return authorizationInfo;
}

当然也可以添加set集合:roles是从数据库查询的当前用户的角色,stringPermissions是从数据库查询的当前用户对应的权限

authorizationInfo.setRoles(roles);
authorizationInfo.setStringPermissions(stringPermissions);

就是说如果在shiro配置文件中添加了filterChainDefinitionMap.put(“/add”,
“perms[权限添加]”);
就说明访问/add这个链接必须要有“权限添加”这个权限才可以访问,如果在shiro配置文件中添加了filterChainDefinitionMap.put(“/add”,
“roles[100002],perms[权限添加]”);
就说明访问/add这个链接必须要有“权限添加”这个权限和具有“100002”这个角色才可以访问。

登录实现

登录过程其实只是处理异常的相关信息,具体的登录验证交给shiro来处理


@RequestMapping("/login")

public String login(HttpServletRequest request, Map<String, Object> map) throws Exception{

System.out.println("HomeController.login()");

// 登录失败从request中获取shiro处理的异常信息。

// shiroLoginFailure:就是shiro异常类的全类名.

String exception = (String) request.getAttribute("shiroLoginFailure");
System.out.println("exception=" + exception);
String msg = "";

if (exception != null) {

if (UnknownAccountException.class.getName().equals(exception)) {
System.out.println("UnknownAccountException -- > 账号不存在:");

msg = "UnknownAccountException -- > 账号不存在:";

} else if (IncorrectCredentialsException.class.getName().equals(exception)) {

System.out.println("IncorrectCredentialsException -- > 密码不正确:");

msg = "IncorrectCredentialsException -- > 密码不正确:";

} else if ("kaptchaValidateFailed".equals(exception)) {

System.out.println("kaptchaValidateFailed -- > 验证码错误");

msg = "kaptchaValidateFailed -- > 验证码错误";

} else {

msg = "else >> "+exception;

System.out.println("else -- >" + exception);

}

}

map.put("msg", msg);
// 此方法不处理登录成功,由shiro进行处理
return "/login";
}

其它dao层和service的代码就不贴出来了大家直接看代码。

测试

1、编写好后就可以启动程序,访问index页面,由于没有登录就会跳转到login页面。登录之后就会跳转到index页面,登录后,有直接在浏览器中输入index页面访问,又会跳转到login页面。上面这些操作时候触发MyShiroRealm.doGetAuthenticationInfo()这个方法,也就是登录认证的方法。

2、登录admin账户,访问:http://127.0.0.1:8080/userInfo/userAdd显示用户添加界面,访问http://127.0.0.1:8080/userInfo/userDel显示403没有权限。上面这些操作时候触发MyShiroRealm.doGetAuthorizationInfo()这个方面,也就是权限校验的方法。

3、修改admin不同的权限进行测试

shiro很强大,这仅仅是完成了登录认证和权限管理这两个功能,更多内容以后有时间再做探讨。

<div class="readall_box csdn-tracking-statistics tracking-click readall_box_nobg" data-pid="blog" data-mod="popu_596" style="display: none;">
<div class="read_more_mask"></div>
<a class="btn btn-large btn-gray-fred read_more_btn" target="_self">阅读全文</a>
</div> <div class="csdn-tracking-statistics" data-pid="blog" data-mod="popu_222"><a href="javascript:void(0);" target="_blank">&nbsp;</a> </div>
<div class="csdn-tracking-statistics" data-pid="blog" data-mod="popu_223"> <a href="javascript:void(0);" target="_blank">&nbsp;</a></div> <script type="text/javascript">
function btndigga() {
$(".csdn-tracking-statistics[data-mod='popu_222'] a").click();
}
function btnburya() {
$(".csdn-tracking-statistics[data-mod='popu_223'] a").click();
}
</script> <div style="clear:both; height:10px;"></div>

springboot(十四):springboot整合shiro-登录认证和权限管理(转)的更多相关文章

  1. spring boot(十四)shiro登录认证与权限管理

    这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求.在Java领域一般有Spring Security ...

  2. springboot(十四):springboot整合shiro-登录认证和权限管理

    这篇文章我们来学习如何使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求.在Java领域一般有Spring Security ...

  3. Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理

    版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...

  4. spring-boot(八) springboot整合shiro-登录认证和权限管理

    学习文章:springboot(十四):springboot整合shiro-登录认证和权限管理 Apache Shiro What is Apache Shiro? Apache Shiro是一个功能 ...

  5. (转)Spring Boot (十四): Spring Boot 整合 Shiro-登录认证和权限管理

    http://www.ityouknow.com/springboot/2017/06/26/spring-boot-shiro.html 这篇文章我们来学习如何使用 Spring Boot 集成 A ...

  6. Spring Boot(十四):spring boot整合shiro-登录认证和权限管理

    Spring Boot(十四):spring boot整合shiro-登录认证和权限管理 使用Spring Boot集成Apache Shiro.安全应该是互联网公司的一道生命线,几乎任何的公司都会涉 ...

  7. Spring Boot (十四): Spring Boot 整合 Shiro-登录认证和权限管理

    这篇文章我们来学习如何使用 Spring Boot 集成 Apache Shiro .安全应该是互联网公司的一道生命线,几乎任何的公司都会涉及到这方面的需求.在 Java 领域一般有 Spring S ...

  8. Spring Boot整合shiro-登录认证和权限管理

    原文地址:http://www.ityouknow.com/springboot/2017/06/26/springboot-shiro.html 这篇文章我们来学习如何使用Spring Boot集成 ...

  9. Springboot-shiro-redis实现登录认证和权限管理

    Springboot-shiro-redis实现登录认证和权限管理 在学习之前: 首先进行一下Apache Shiro和Shiro比较: Apache Shiro是一个功能强大.灵活的,开源的安全框架 ...

随机推荐

  1. PHP 7.1安装xhprof进行性能分析

    安装扩展该 xhprof扩展版本是从 https://github.com/longxinH/xhprof 获取的(第三方的一个库,官方版本不支持php7) 下载并编译xhprof扩展在web的htm ...

  2. iOS QQ第三方登实现

    我们常常会见到应用登陆的时候会有QQ,微信,微博等的第三方登陆 如图: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvbHdqb2syMDA3/font/5 ...

  3. 实战c++中的vector系列--copy set to vector(别混淆了reserve和resize)

    stl算法中有个copy函数.我们能够轻松的写出这种代码: #include <iostream> #include <algorithm> #include <vect ...

  4. IK分词器插件elasticsearch-analysis-ik 6.1.1

    http://88250.b3log.org/full-text-search-elasticsearch#b3_solo_h3_0 IK分词器插件 (1)源码 https://github.com/ ...

  5. IAR for STM8介绍、下载、安装与注册--转

    Ⅰ.写在前面 本文讲述的内容是IAR for STM8的介绍.下载.安装与注册,其安装.注册过程和IAR for ARM类似,如果需要了解IAR for ARM相关的文章,可以到我博客,或微信公众号查 ...

  6. STM32介绍以及与通常ARM的区别

    ARM是英国的芯片设计公司,其最成功的莫过于32位嵌入式CPU核----ARM系列,最常用的是ARM7和ARM9,ARM公司主要提供IP核,就是CPU的内核结构,只包括最核心的部分,并不是完整的处理器 ...

  7. 关于使用toFixed()函数时报错"toFixed() is not a function"的问题

    toFixed()函数只有数字类型的参数才可使用,字符串类型的参数需用parseFloat或者parseInt转换后再使用

  8. BZOJ2565: 最长双回文串(Manacher)

    Description 顺序和逆序读起来完全一样的串叫做回文串.比如acbca是回文串,而abc不是(abc的顺序为“abc”,逆序为“cba”,不相同).输入长度为n的串S,求S的最长双回文子串T, ...

  9. 【习题 7-8 UVA-12107】Digit Puzzle

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 迭代加深搜索. 枚举最大层数.(也即改变的数字个数 然后枚举第一个改哪个数字,第二个改哪个数字.. 一定要注意字典序问题. 每次优先 ...

  10. jsp 用shiro 的判断 是否有菜单查看的权限

    实例:spring-shiro.xml 123 /admin/repairType/index = roles["ROLE_ADMIN"]/admin/user=roles[&qu ...