关于shiro的概念和知识本篇不做详细介绍,但是shiro的概念还是需要做做功课的要不无法理解它的运作原理就无法理解使用shiro;

本篇主要讲解如何使用shiro实现登录认证,下篇讲解使用shiro实现权限控制

要实现shiro和springboot的整合需要以下几大步骤:

  1. 生成用户表
  2. 引入shiro依赖
  3. 添加shiro配置文件
  4. 添加自定义的realm
  5. 登录操作触发验证
  6. 细节处理

下面我们一步步的详细介绍:

一、生成用户表

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实现登录认证的更多相关文章

  1. SpringBoot 整合 Shiro 密码登录与邮件验证码登录(多 Realm 认证)

    导入依赖(pom.xml)  <!--整合Shiro安全框架--> <dependency> <groupId>org.apache.shiro</group ...

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

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

  3. (八) SpringBoot起飞之路-整合Shiro详细教程(MyBatis、Thymeleaf)

    兴趣的朋友可以去了解一下前几篇,你的赞就是对我最大的支持,感谢大家! (一) SpringBoot起飞之路-HelloWorld (二) SpringBoot起飞之路-入门原理分析 (三) Sprin ...

  4. SpringBoot系列十二:SpringBoot整合 Shiro

    声明:本文来源于MLDN培训视频的课堂笔记,写在这里只是为了方便查阅. 1.概念:SpringBoot 整合 Shiro 2.具体内容 Shiro 是现在最为流行的权限认证开发框架,与它起名的只有最初 ...

  5. SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)

    首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cooki ...

  6. SpringBoot系列(十二)过滤器配置详解

    SpringBoot(十二)过滤器详解 往期精彩推荐 SpringBoot系列(一)idea新建Springboot项目 SpringBoot系列(二)入门知识 springBoot系列(三)配置文件 ...

  7. SpringBoot整合Shiro 四:认证+授权

    搭建环境见: SpringBoot整合Shiro 一:搭建环境 shiro配置类见: SpringBoot整合Shiro 二:Shiro配置类 shiro整合Mybatis见:SpringBoot整合 ...

  8. spring-boot整合shiro作权限认证

    spring-shiro属于轻量级权限框架,即使spring-security更新换代,市场上大多数企业还是选择shiro 废话不多说  引入pom文件 <!--shiro集成spring--& ...

  9. SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)在pom.xml中添加依赖: <properties> <shi ...

随机推荐

  1. 构造方法(和python初始化变量类似)

    public class Demo1 { int  name2=1; public Demo1(int name) { name=name2; } public Demo1() { } public ...

  2. python中验证码连通域分割的方法详解

    python中验证码连通域分割的方法详解 这篇文章主要给大家介绍了关于python中验证码连通域分割的相关资料,文中通过示例代码介绍的非常详细,对大家学习或者使用python具有一定的参考学习价值,需 ...

  3. (十四)访问标志 Access_flags

    一.概念 上一章节讲到了常量池,如下图,常量池之后便是访问标志acess_flags,占2个字节(u2). 二.例子 编写一个接口. public interface Test{ public fin ...

  4. 微信小程序技巧记录

    1.直接在app.json中添加pages,会自动按照路径生成page目录文件: 2.动态修改样式: /** * 页面的初始数据 */ data: { authorInfo: [], article: ...

  5. 《MySQL必知必会》学习笔记——第30章 改善性能

    本章将付息与MySQL性能有关的某些要点. 30.1 改善性能 数据库管理员把他们生命中的相当一部分时间花在了调整.试验以改善DBMS性能之上.在诊断英勇的滞缓现象和性能问题时,性能不良的数据库(以及 ...

  6. IE6/IE7/IE8 JQuery下resize事件执行多次的解决方法

    在使用jQuery的resize事件时发现每次改变浏览器的窗口大小时resize时间会执行两次,百度搜索了一下找到一个解决的方法,使用setTimeout来解决这个问题代码如下: var resize ...

  7. 05点睛Spring4.1-国际化

    5.1 ReloadableResourceBundleMessageSource 使用ReloadableResourceBundleMessageSource可获得不同语言的配置 此处是全局配置, ...

  8. IDEA springboot maven 引用第三方jar包

    1.在左侧项目里新建一个 lib 文件夹,把第三方jar 包复制进去 . 2.修改pom.xml ,dependencies配置节增加,plugins 配置节做修改. dependencies配置节增 ...

  9. vs.Debug.vector迭代器报错(_ITERATOR_DEBUG_LEVEL)

    1.vs2017.Win7x64 std::vector<ULONG>,在 使用 *iter 取某个 ULONG时 报错,release不报错,报错信息: ZC:具体原理不明,暂时的解决方 ...

  10. Makefile中宏定义

    实际上是gcc命令支持-D宏定义,相当于C中的全局#define: gcc -D name gcc -D name=definition Makefile中可以定义变量(和宏很像),但是是给make解 ...