【视频&交流平台】
http://study.163.com/course/introduction.htm?courseId=1004329008&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
http://study.163.com/course/introduction.htm?courseId=1004638001&utm_campaign=commission&utm_source=400000000155061&utm_medium=share
https://gitee.com/happyangellxq520/spring-boot
http://412887952-qq-com.iteye.com/blog/2321532
【原创文章,转载请注明出处】
上一节写到了,已经是无状态的,这节我们讲讲怎么加入请求控制拦截。
(1)加入请求控制拦截代码
以下这部分可能会有点难,需要集中注意力进行学习哦:
首先我们先编写一个工具类,对参数信息处理——加密解密之消息摘要算法,具体代码如下:
package com.kfit.config;
import org.apache.commons.codec.binary.Hex;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.util.List;
import java.util.Map;
/**
* Java 加密解密之消息摘要算法
* @author Angel --守护天使
* @version v.0.1
* @date 2017年2月25日
*/
public class HmacSHA256Utils {
public static String digest(String key, String content) {
try {
Mac mac = Mac.getInstance("HmacSHA256");
byte[] secretByte = key.getBytes("utf-8");
byte[] dataBytes = content.getBytes("utf-8");
SecretKey secret = new SecretKeySpec(secretByte, "HMACSHA256");
mac.init(secret);
byte[] doFinal = mac.doFinal(dataBytes);
byte[] hexB = new Hex().encode(doFinal);
return new String(hexB, "utf-8");
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@SuppressWarnings("unchecked")
public static String digest(String key, Map<String, ?> map) {
StringBuilder s = new StringBuilder();
for(Object values : map.values()) {
if(valuesinstanceof String[]) {
for(String value : (String[])values) {
s.append(value);
}
} elseif(valuesinstanceof List) {
for(String value : (List<String>)values) {
s.append(value);
}
} else {
s.append(values);
}
}
return digest(key, s.toString());
}
}
接下来我们需要一个AuthenticationToken保存我们的身份信息,比如用户名,客户端传入的消息摘要,还有客户端传入的参数map等,具体代码如下:
package com.kfit.config;
import java.util.Map;
import org.apache.shiro.authc.AuthenticationToken;
/**
* 用于授权的Token对象:
*
* 用户身份即用户名;
* 凭证即客户端传入的消息摘要。
* @author Angel --守护天使
* @version v.0.1
* @date 2017年2月25日
*/
public class StatelessAuthenticationToken implements AuthenticationToken{
private static final long serialVersionUID = 1L;
private String username;//用户身份即用户名;
private Map<String,?> params;//参数.
private String clientDigest;//凭证即客户端传入的消息摘要。
public StatelessAuthenticationToken() {
}
public StatelessAuthenticationToken(String username, Map<String, ?> params, String clientDigest) {
super();
this.username = username;
this.params = params;
this.clientDigest = clientDigest;
}
public StatelessAuthenticationToken(String username, String clientDigest) {
super();
this.username = username;
this.clientDigest = clientDigest;
}
@Override
public Object getPrincipal() {
return username;
}
@Override
public Object getCredentials() {
return clientDigest;
}
public String getUsername() {
return username;
}
publicvoid setUsername(String username) {
this.username = username;
}
public Map<String, ?> getParams() {
return params;
}
publicvoid setParams(Map<String, ?> params) {
this.params = params;
}
public String getClientDigest() {
return clientDigest;
}
publicvoid setClientDigest(String clientDigest) {
this.clientDigest = clientDigest;
}
}
好了,准备工作好了之后,我们就可以开始编写核心的代码了,首先是第一个访问控制过滤器,拦截我们的请求,我们主要是处理onAccessDenied()方法,接收到请求的参数,组装成StatelessAuthenticationToken,然后委托为Realm进行处理,具体代码思路如下:
//2、客户端传入的用户身份;
//3、客户端请求的参数列表;
//4、生成无状态Token
//5、委托给Realm进行登录
具体的代码如下:
package com.kfit.config;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;
import org.apache.shiro.web.filter.AccessControlFilter;
/**
* 访问控制过滤器
* @author Angel --守护天使
* @version v.0.1
* @date 2017年2月25日
*/
public class StatelessAccessControlFilter extends AccessControlFilter{
/**
* 先执行:isAccessAllowed 再执行onAccessDenied
*
* isAccessAllowed:表示是否允许访问;mappedValue就是[urls]配置中拦截器参数部分,
* 如果允许访问返回true,否则false;
*
* 如果返回true的话,就直接返回交给下一个filter进行处理。
* 如果返回false的话,回往下执行onAccessDenied
*/
@Override
protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue)
throws Exception {
System.out.println("StatelessAuthcFilter.isAccessAllowed()");
return false;
}
/**
* onAccessDenied:表示当访问拒绝时是否已经处理了;如果返回true表示需要继续处理;
* 如果返回false表示该拦截器实例已经处理了,将直接返回即可。
*/
@Override
protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception {
System.out.println("StatelessAuthcFilter.onAccessDenied()");
//1、客户端生成的消息摘要
String clientDigest = request.getParameter("digest");
//2、客户端传入的用户身份
String username = request.getParameter("username");
//3、客户端请求的参数列表
Map<String, String[]> params = new HashMap<String, String[]>(request.getParameterMap());
params.remove("digest");//为什么要移除呢?签名或者消息摘要算法的时候不能包含digest.
//4、生成无状态Token
StatelessAuthenticationToken token = new StatelessAuthenticationToken(username,params,clientDigest);
// UsernamePasswordToken token = new UsernamePasswordToken(username,clientDigest);
try {
//5、委托给Realm进行登录
getSubject(request, response).login(token);
} catch (Exception e) {
e.printStackTrace();
//6、登录失败
onLoginFail(response);
return false;//就直接返回给请求者.
}
return true;
}
//登录失败时默认返回401 状态码
private void onLoginFail(ServletResponse response) throws IOException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpResponse.getWriter().write("login error");
}
}
紧接着请求就到了我们的Realm代码,所以我们需要编写一个Realm来进行身份验证下,这里的核心就是获取到AccessControlFilter传递过来的StatelessAuthenticationToken中的参数进行消息摘要,然后生成对象SimpleAuthenticationInfo交给Shiro进行比对,具体代码如下:
package com.kfit.config;
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;
public class StatelessAuthorizingRealm extends AuthorizingRealm{
/**
* 仅支持StatelessToken 类型的Token,
* 那么如果在StatelessAuthcFilter类中返回的是UsernamePasswordToken,那么将会报如下错误信息:
* Please ensure that the appropriate Realm implementation is configured correctly or
* that the realm accepts AuthenticationTokens of this type.StatelessAuthcFilter.isAccessAllowed()
*/
@Override
publicboolean supports(AuthenticationToken token) {
return token instanceof StatelessAuthenticationToken;
}
/**
* 身份验证
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("StatelessRealm.doGetAuthenticationInfo()");
StatelessAuthenticationToken statelessToken = (StatelessAuthenticationToken)token;
String username = (String)statelessToken.getPrincipal();//不能为null,否则会报错的.
//根据用户名获取密钥(和客户端的一样)
String key = getKey(username);
//在服务器端生成客户端参数消息摘要
String serverDigest = HmacSHA256Utils.digest(key, statelessToken.getParams());
System.out.println(serverDigest+","+statelessToken.getCredentials());
//然后进行客户端消息摘要和服务器端消息摘要的匹配
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
username,
serverDigest,
getName());
return authenticationInfo;
}
/**
* 授权
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("StatelessRealm.doGetAuthorizationInfo()");
//根据用户名查找角色,请根据需求实现
String username = (String) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
//这里模拟admin账号才有role的权限.
if("admin".equals(username)){
authorizationInfo.addRole("admin");
}
return authorizationInfo;
}
//得到密钥,此处硬编码一个.
private String getKey(String username) {
return "andy123456";
}
}
剩下的就是将我们的这些配置到ShiroConfiguration类中(新加的代码有Add.4.x),具体代码如下:
package com.kfit.config;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.DefaultSessionManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.mgt.DefaultWebSubjectFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* shiro配置类.
* @author Angel --守护天使
* @version v.0.1
* @date 2017年2月25日
*/
@Configuration
public class ShiroConfiguration {
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager){
ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
factoryBean.setSecurityManager(securityManager);
//Add.4.2.start
factoryBean.getFilters().put("statelessAuthc", statelessAuthcFilter());
//拦截器.
Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>();
filterChainDefinitionMap.put("/**", "statelessAuthc");
factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
//Add.4.2.end
return factoryBean;
}
/**
* shiro安全管理器:
* 主要是身份认证的管理,缓存管理,cookie管理,
* 所以在实际开发中我们主要是和SecurityManager进行打交道的
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
//Add.2.2
securityManager.setSubjectFactory(subjectFactory());
//Add.2.5
securityManager.setSessionManager(sessionManager());
//Add.4.4
securityManager.setRealm(statelessRealm());
/*
* 禁用使用Sessions 作为存储策略的实现,但它没有完全地禁用Sessions
* 所以需要配合context.setSessionCreationEnabled(false);
*/
//Add.2.3
((DefaultSessionStorageEvaluator)((DefaultSubjectDAO)securityManager.getSubjectDAO()).getSessionStorageEvaluator()).setSessionStorageEnabled(false);
return securityManager;
}
/**
* Add.2.1
* subject工厂管理器.
* @return
*/
@Bean
public DefaultWebSubjectFactory subjectFactory(){
StatelessDefaultSubjectFactory subjectFactory = new StatelessDefaultSubjectFactory();
return subjectFactory;
}
/**
* Add.2.4
* session管理器:
* sessionManager通过sessionValidationSchedulerEnabled禁用掉会话调度器,
* 因为我们禁用掉了会话,所以没必要再定期过期会话了。
* @return
*/
@Bean
public DefaultSessionManager sessionManager(){
DefaultSessionManager sessionManager = new DefaultSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(false);
return sessionManager;
}
/**
* Add.4.3
* 自己定义的realm.
* @return
*/
@Bean
public StatelessAuthorizingRealm statelessRealm(){
StatelessAuthorizingRealm realm = new StatelessAuthorizingRealm();
return realm;
}
/**
* Add.4.1
* 访问控制器.
* @return
*/
@Bean
public StatelessAccessControlFilter statelessAuthcFilter(){
StatelessAccessControlFilter statelessAuthcFilter = new StatelessAccessControlFilter();
return statelessAuthcFilter;
}
}
好了,到这里终于差不多了,赶紧测试下吧,访问地址:
这里的digest是根据参数生成的,必须为如下:
df7f1595bd5682638556072c8ccde5edadcd807a829373d21af38fb1bc707da7
否则就输入其它的直进行测试的话,就会看到login error。到这里基本算是完成了。
【视频&交流平台】
http://study.163.com/course/introduction.htm?courseId=1004523002
http://412887952-qq-com.iteye.com/blog/2321532
======================================
Spring Boot Shiro视频实战篇【已更新】
======================================
适合人群
有Spring Boot基础的人群。
使用技术
(1)spring boot(整合框架)
(2)spring mvc
(3)spring data jpa(持久化操作)
(4)shiro(安全框架)
(5)thymeleaf(模板引擎)
(6)ehcache(缓存管理)
(7)mysql(数据库)
(8)js/css/img(静态资源使用)
(9)kaptcha(验证码库)
课程目录
1. Spring Boot Shiro介绍
2. Spring Boot 搭建无Shiro的框架
3. Spring Boot Shiro拦截
4. Spring Boot Shiro身份认证准备工作
5. Spring Boot Shiro身份认证
6. Spring Boot Shiro权限控制
7. Spring Boot Shiro缓存
8. Spring Boot Shiro记住密码
9. Spring Boot Shiro登录成功之后下载favicon.ico
10. Spring Boot 在thymeleaf使用shiro标签
11. Spring Boot Shiro密码加密算法
12.Spring Boot Shiro使用JS-CSS-IMG
13. Spring Boot Shiro限制登录尝试次数
14.Spring Boot Shiro 验证码
相关推荐
在本教程中,我们将深入探讨如何使用Spring Boot与Apache Shiro进行权限管理。Spring Boot以其简洁的配置和快速的应用开发而闻名,而Shiro则是一个轻量级的安全框架,适用于身份验证、授权、会话管理和安全性相关的...
在本教程中,我们将深入探讨如何使用Spring Boot与Apache Shiro进行权限管理。Spring Boot以其简洁的配置和快速的应用开发能力而备受青睐,而Shiro则是一个轻量级的安全框架,用于实现用户认证、授权和会话管理。...
4. `shiro.ini` 或 `shiro.yml`:Shiro 的配置文件,定义了过滤器链和 Realm 设置。 5. `WebSecurityInitializer.java`:初始化 Shiro 过滤器链的配置。 通过以上步骤,我们可以构建一个集成了 Spring Boot 和 ...
在学习过程中,提供的《从零开始学Spring Boot》PDF电子书会详细介绍Spring Boot的各个组件和使用方式,包括自动配置、起步依赖、Actuator监控、外部配置、测试等方面。而《Shiro教程》则会详细阐述Shiro的各个方面...
**Spring Boot 集成 Shiro 深度解析** Spring Boot 是一款基于 Spring 的轻量级框架,它简化了 Spring 应用的初始搭建以及开发过程。而 Apache Shiro 是一个强大且易用的 Java 安全框架,提供了认证、授权、加密和...
在本教程中,我们将深入探讨如何使用Spring Boot和Apache Shiro进行权限管理。Spring Boot以其简洁的配置和快速的应用开发能力而闻名,而Shiro则是一个强大的安全管理框架,提供了认证、授权、会话管理和安全加密等...
《Spring Boot整合Shiro实战详解》 在现代Java Web开发中,Spring Boot以其简洁的配置、快速的开发体验,已经成为主流框架。而Apache Shiro作为一款强大的安全管理框架,提供了认证、授权、会话管理和安全加密等...
在本文中,我们将探讨如何利用Spring Boot和Apache Shiro构建一个权限管理系统。Spring Boot以其便捷的启动和配置方式,使得快速开发变得简单。而Shiro则是一个轻量级的安全框架,用于实现用户认证和授权。 首先,...
3. 前后端分离前端使用Vue.js和ElementUI,后端使用Spring Boot和Shiro,实现前后端分离的架构。 4. 动态路由前端根据用户的权限动态生成路由,隐藏无权限的菜单和按钮。 5. 全局异常处理统一处理系统中的异常,返回...
Spring Boot学习之Shiro源码【学习狂神说,自己手动书写,可以实现正常所需的功能】 Spring Boot学习之Shiro源码【学习狂神说,自己手动书写,可以实现正常所需的功能】 Spring Boot学习之Shiro源码【学习狂神说,...
Spring Boot Shiro Demo项目是一个基于Spring Boot框架与Apache Shiro实现的权限管理示例,旨在帮助开发者快速理解和应用Shiro进行权限控制。相比Spring Security,Shiro通常被认为更易于理解和使用,更适合小型到...
【Spring Boot整合Shiro搭建权限管理系统】 在Java后端开发中,Spring Boot因其简洁的配置和强大的功能,已经成为构建Web应用的首选框架。而Apache Shiro则是一个强大且易用的Java安全框架,用于处理认证、授权、...
3. **创建Shiro配置类**:在Spring Boot项目中,我们需要创建一个配置类来初始化Shiro的环境,包括安全过滤器链的配置、Realm的定义以及Session管理等。例如: ```java @Configuration public class ShiroConfig { ...
首先,让我们从创建一个 Spring Boot 项目开始: 1. 创建 Maven 工程: 使用 Maven 作为构建工具是标准做法,因为它提供了依赖管理和构建自动化功能。新建一个 Maven 项目,并在 `pom.xml` 文件中引入 Spring Boot...
在现代Web开发中,Spring Boot和Apache Shiro是两个非常重要的框架。Spring Boot以其便捷的配置和快速的应用启动而受到广大开发者的喜爱,而Apache Shiro则是一个强大的安全管理框架,负责处理认证、授权、会话管理...
1.3 spring boot起步之Hello World 1.4 Spring Boot返回json数据 1.5 Spring Boot热部署 1.6 Spring Boot使用别的json解析框架 1.7 全局异常捕捉 1.8 Spring Boot datasource - mysql 1.9 JPA - Hibernate 1.10 使用...
### Spring Boot整合Shiro搭建权限管理系统知识点解析 #### 一、Spring Boot与Shiro简介 - **Spring Boot**: 是一种简化Spring应用开发的框架,它提供了自动配置、依赖管理等功能,使得开发者能够快速构建独立的...
Spring Boot、Shiro和MyBatis这三大框架的组合提供了一种高效且灵活的方式来实现这一目标。本项目通过集成这三个工具,能够根据用户的登录身份展示不同的权限菜单,确保了用户只能访问他们被授权的功能。 **Spring ...
整合Spring Boot与Shiro,首先需要在项目中引入Shiro的相关依赖。在`pom.xml`文件中添加Spring Boot对Shiro的支持,然后配置SecurityManager,并实现自己的Realm以处理认证和授权逻辑。接下来,可以编写过滤器链来...
在开始介绍如何使用Spring Boot整合Shiro搭建权限管理系统之前,我们首先简要回顾一下Spring Boot的基础知识。 ##### 1. 新建一个Maven工程 为了创建一个Spring Boot项目,首先需要使用Maven或者Gradle作为构建...