springboot系列(十)springboot整合shiro实现登录认证
关于shiro的概念和知识本篇不做详细介绍,但是shiro的概念还是需要做做功课的要不无法理解它的运作原理就无法理解使用shiro;
本篇主要讲解如何使用shiro实现登录认证,下篇讲解使用shiro实现权限控制
要实现shiro和springboot的整合需要以下几大步骤:
- 生成用户表
- 引入shiro依赖
- 添加shiro配置文件
- 添加自定义的realm
- 登录操作触发验证
- 细节处理
下面我们一步步的详细介绍:
一、生成用户表
CREATE TABLE `sys_user` (
`user_id` bigint(20) NOT NULL AUTO_INCREMENT,
`username` varchar(50) NOT NULL COMMENT '用户名',
`password` varchar(100) DEFAULT NULL COMMENT '密码',
`salt` varchar(20) DEFAULT NULL COMMENT '盐',
`email` varchar(100) DEFAULT NULL COMMENT '邮箱',
`mobile` varchar(100) DEFAULT NULL COMMENT '手机号',
`status` tinyint(4) DEFAULT NULL COMMENT '状态 0:禁用 1:正常',
`dept_id` bigint(20) DEFAULT NULL COMMENT '部门ID',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`user_id`),
UNIQUE KEY `username` (`username`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8 COMMENT='系统用户';
二、引入shiro依赖
<!-- Apache shiro依赖 只需要引入本依赖 shiro-spring 会自动引入shiro-web和shiro-core依赖-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.3.2</version>
</dependency>
三、添加shiro的配置文件(本篇使用的是@Configuration注解java类的方式,也可以使用xml的方式)
package com.chuhouqi.demo.shiro; import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.session.mgt.SessionManager;
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.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map; @Configuration
public class ShiroConfig { @Bean("sessionManager")
public SessionManager sessionManager(){
DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
sessionManager.setSessionValidationSchedulerEnabled(true);
sessionManager.setSessionIdUrlRewritingEnabled(false);
//sessionManager.setSessionIdCookieEnabled(false);
return sessionManager;
} @Bean("securityManager")
public SecurityManager securityManager(UserRealm userRealm, SessionManager sessionManager) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(userRealm);
securityManager.setSessionManager(sessionManager); return securityManager;
} @Bean("shiroFilter")
public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean();
shiroFilter.setSecurityManager(securityManager);
shiroFilter.setLoginUrl("/login");
shiroFilter.setSuccessUrl("/index");
shiroFilter.setUnauthorizedUrl("/403"); Map<String, String> filterMap = new LinkedHashMap<>();
filterMap.put("/druid/**", "anon");
filterMap.put("/api/**", "anon");
filterMap.put("/login", "anon");
filterMap.put("/registe", "anon");
filterMap.put("/registe.html", "anon");
filterMap.put("/**/*.css", "anon");
filterMap.put("/**/*.js", "anon");
// filterMap.put("/login.html", "anon");
filterMap.put("/fonts/**", "anon");
filterMap.put("/plugins/**", "anon");
filterMap.put("/swagger/**", "anon");
filterMap.put("/favicon.ico", "anon");
filterMap.put("/captcha.jpg", "anon");
filterMap.put("/", "anon");
filterMap.put("/**", "authc");
shiroFilter.setFilterChainDefinitionMap(filterMap); return shiroFilter;
} @Bean("lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} @Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator proxyCreator = new DefaultAdvisorAutoProxyCreator();
proxyCreator.setProxyTargetClass(true);
return proxyCreator;
} @Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
advisor.setSecurityManager(securityManager);
return advisor;
} }
四、添加自定义的realm(实现认证和授权)
package com.chuhouqi.demo.shiro; import com.chuhouqi.demo.common.utils.ShiroUtil;
import com.chuhouqi.demo.entity.User;
import com.chuhouqi.demo.service.IUserService;
import org.apache.shiro.authc.*;
import org.apache.shiro.authc.credential.CredentialsMatcher;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component; @Component
public class UserRealm extends AuthorizingRealm { @Autowired
private IUserService userService; @Override
/**
* 权限授权
*/
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) { return null;
} @Override
/**
* 登录认证
*/
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名
String username = (String) token.getPrincipal(); //根据用户名查询用户信息
User user = userService.getUser(username);
// 账号不存在
if (user == null) {
throw new UnknownAccountException("账号不存在");
}
// 账号锁定
if (user.getStatus() == 0) {
throw new LockedAccountException("账号已被锁定,请联系管理员");
}
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(
user.getUsername(),
user.getPassword(),
ByteSource.Util.bytes(user.getSalt()),
getName()
);
return info; } /**
* 设置密码比较器为HashedCredentialsMatcher
* @param credentialsMatcher
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
shaCredentialsMatcher.setHashAlgorithmName(ShiroUtil.hashAlgorithmName);
shaCredentialsMatcher.setHashIterations(ShiroUtil.hashIterations);
super.setCredentialsMatcher(shaCredentialsMatcher);
} }
五、登录操作触发验证
package com.chuhouqi.demo.controller; import com.chuhouqi.demo.common.utils.ShiroUtil;
import com.chuhouqi.demo.entity.User;
import com.chuhouqi.demo.service.IUserService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping; @Controller
public class LoginController { private static Logger logger = LoggerFactory.getLogger(LoginController.class); @Autowired
private IUserService userService; @GetMapping("/login")
String login() {
return "login";
} @RequestMapping("/login")
public String login(String username, String password, Model model){
try {
Subject subject = SecurityUtils.getSubject();
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
subject.login(token);
}catch (UnknownAccountException e) {
logger.error(e.getMessage());
model.addAttribute("msg",e.getMessage());
return "login";
}catch (IncorrectCredentialsException e) {
logger.error(e.getMessage());
model.addAttribute("msg","账号或密码不正确");
return "login";
}catch (LockedAccountException e) {
logger.error(e.getMessage());
model.addAttribute("msg","账号已被锁定,请联系管理员");
return "login";
}catch (AuthenticationException e) {
logger.error(e.getMessage());
model.addAttribute("msg","账户验证失败");
return "login";
}
return "index";
} @RequestMapping("/registe")
public String registe(User user){
userService.saveUser(user);
return "ok";
} @RequestMapping("/logout")
public String logout(){
ShiroUtil.logout();
return "redirect:/login";
} }
验证:
启动项目,然后随便请求一个路径都会被shiro配置的filter拦截器进行拦截,如果请求的路径需要权限认证就会进入shiro的认证管理中,如果当前用户没有登录就会调整到登录页面;
六、细节处理:
上面的介绍只是给出了一个大概的流程,其中有很多细节还是要特比注意的要不会导致认证失败,下面我们看一下有哪些细节需要处理
1、用户密码加密处理
在数据库中存储的用户密码不应该是123456这样的密码明文,被不法分子看到是很危险的,所以数据库中的密码应该是对密码进行加密后的密文,而且还要求这个加密算法是不可逆的,即由加密后的字符串不能反推回来原来的密码,如果能反推回来那这个加密是没有意义的。
现在常用的加密算法有: MD5,SHA1
而且shiro提供了SimpleHash这个加密工具来实现密码加密:
public final static String hashAlgorithmName = "SHA-256";//加密算法
public final static int hashIterations = 16;//hash加密次数 public static String encrypt(String pwd,String salt){
String newPassword = new SimpleHash(hashAlgorithmName,pwd,salt,hashIterations).toHex();
return newPassword;
}
如果两个人的密码一样,即存在数据表里中的两个加密后的字符串一样,然而我们希望即使两个人的密码一样,加密后的两个字符串也不一样。即需要用到MD5盐值加密。
盐值需要唯一: 一般使用随机字符串或 user id
这里提供一个工具:
String salt = RandomStringUtils.randomAlphanumeric(20);//使用随机数函数生成salt
2、配置shiro的密码比较器
上面我们用加密算法实现了密码的明文加密,现在数据库中存储的是密码密文,用户登录时使用的密码原文,如果不告诉shiro我们的密码加密算法逻辑,shiro是使用默认的比较器
进行的简单的密码比较(即使用数据库中的密码密文和用户登录时输入的密码明文进行比较),显而易见这样比较是不会成功的所以我们要告诉shiro 我们是使用的加密算法,
实现过程很简单:在我们自定义的UserRealm中添加如下配置
/**
* 设置密码比较器为HashedCredentialsMatcher
* @param credentialsMatcher
*/
@Override
public void setCredentialsMatcher(CredentialsMatcher credentialsMatcher) {
HashedCredentialsMatcher shaCredentialsMatcher = new HashedCredentialsMatcher();
shaCredentialsMatcher.setHashAlgorithmName(ShiroUtil.hashAlgorithmName);//这里就是我们进行密码加密的算法
shaCredentialsMatcher.setHashIterations(ShiroUtil.hashIterations);//加密循环次数
super.setCredentialsMatcher(shaCredentialsMatcher);
}
springboot系列(十)springboot整合shiro实现登录认证的更多相关文章
- SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)
导入依赖(pom.xml) <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</group ...
- Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...
- (八) SpringBoot起飞之路-整合Shiro详细教程(MyBatis、Thymeleaf)
兴趣的朋友可以去了解一下前几篇,你的赞就是对我最大的支持,感谢大家! (一) SpringBoot起飞之路-HelloWorld (二) SpringBoot起飞之路-入门原理分析 (三) Sprin ...
- SpringBoot系列十二:SpringBoot整合 Shiro
声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Shiro 2.具体内容 Shiro 是现在最为流行的权限认证开发框架,与它起名的只有最初 ...
- SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)
首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cooki ...
- SpringBoot系列(十二)过滤器配置详解
SpringBoot(十二)过滤器详解 往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件 ...
- SpringBoot整合Shiro 四:认证+授权
搭建环境见: SpringBoot整合Shiro 一:搭建环境 shiro配置类见: SpringBoot整合Shiro 二:Shiro配置类 shiro整合Mybatis见:SpringBoot整合 ...
- spring-boot整合shiro作权限认证
spring-shiro属于轻量级权限框架,即使spring-security更新换代,市场上大多数企业还是选择shiro 废话不多说 引入pom文件 <!--shiro集成spring--& ...
- SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存
项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)在pom.xml中添加依赖: <properties> <shi ...
随机推荐
- LeetCode_344. Reverse String
344. Reverse String Easy Write a function that reverses a string. The input string is given as an ar ...
- 【k8s label】对node添加删除label,并根据label筛选节点
添加 kubectl label nodes kube-node label_name=label_value kubectl label nodes 1.1.1.1 label_name=label ...
- centos配置/etc/mail.rc发邮件
安装mailx: yum install mailx vi /etc/mail.rc set from=524755798@qq.comset smtp="smtps://smtp.qq.c ...
- MSP430FR6972驱动模块模组调试
1. 说是会进入晶振的中断 #pragma vector=UNMI_VECTOR 2. 打了断点没进入,猜测是串口被世龙修改后,串口波特率不对,重新改回原来的,AT+NATSPEED?一直发送这个命令 ...
- 未处理的异常:system.io.file load exception:无法加载文件或程序集“ 。。。。 找到的程序集的清单定义与程序集引用不匹配。
问题描述: 添加控制器的时候,突然就报了这个错: Unhandled Exception: System.IO.FileLoadException: Could not load file or as ...
- SQL在线自助查询
数据的日常查询统计分析是高频的需求,然而生产数据库由于安全.管理等方面的要求,仅仅对部分人员开发,例如DBA,总监等, 其他人员都要通过DBA才能查询数据,十分不便. 为了让DBA免于日常繁琐的工作, ...
- RabbitMQ官方教程一Hello World(GOLANG语言实现)
介绍 RabbitMQ是消息中间件:它接受并转发消息. 您可以将其视为邮局系统:将要发送的邮件放在邮箱中时, 可以确保邮递员最终将邮件传递给收件人. 以此类推,RabbitMQ是一个邮箱,一个邮局和一 ...
- C++ 优先队列priority_queue用法【转载】
priority_queue 对于基本类型的使用方法相对简单.他的模板声明带有三个参数,priority_queue<Type, Container, Functional>Type 为数 ...
- Ubuntu18.04 安装MySQL
安装 #命令1 sudo apt-get update #命令2 sudo apt-get install mysql-server 初始化 sudo mysql_secure_installatio ...
- python基础篇(四)
PYTHON基础篇(四) 内置函数 A:基础数据相关(38) B:作用域相关(2) C:迭代器,生成器相关(3) D:反射相关(4) E:面向对象相关(9) F:其他(12) 匿名函数 A:匿名函数基 ...