关于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. Laya的图文混排

    参考: Laya图文混排 Laya的图文混排教程 编辑模式F9,增加laya.html.js库 在层级窗口右键,添加一个HtmlDivElement组件 大致的原理: 1. 例如输入框的字符串是 &q ...

  2. 【427】Graph 实现 以及 DFS & BFS

    目录: Graph 实现 二维数组实现 Linked List 实现 DFS:深度优先搜索 stack 实现 recursion 实现 BFS:广度优先搜索(queue) 其他应用 非连通图遍历 - ...

  3. spring 通过注解装配Bean

    使用注解的方式可以减少XML的配置,注解功能更为强大,它既能实现XML的功能,也提供了自动装配的功能,采用了自动装配后,程序员所需要做的决断就少了,更加有利于对程序的开发,这就是“约定优于配置”的开发 ...

  4. AD 常用策略-修改本地管理员密码,禁用非administrator帐户,删除非administrator帐户

    这个是用启动脚本实现的. 我放在计算机策略下了. 另存为VBS格式即可 修改第三行“123qwe!@#”,引号中的就是你的新密码. 一:禁用非administrator帐户 strComputer = ...

  5. 使用mousedown、mousemove、mouseup实现拖拽效果

    如何实现一个元素的拖拽效果,使用原生的js实现,习惯了jquery的同学们,你们自己写了吗?N久使用mvvm框架,不写jquery的东西,感觉自己完全不会了. 话不多说,直接上code.本例子以简单的 ...

  6. filebeat输出到kafka

    # cat filebeat.yml filebeat.inputs: - type: log enabled: true tail_files: true paths: - /data/www.ex ...

  7. CF1281B Azamon Web Services

    思路: 贪心,找到将s至多交换一次所能得到的字典序最小的字符串,再与c比较. 实现: #include <bits/stdc++.h> using namespace std; int m ...

  8. 高级UI-事件传递

    事件传递在Android中有着举足轻重的作用,那么事件的传递在Android中又是怎么样实现的呢,在这里我们将进一步探讨Android的事件传递机制 从一个例子入手 首先是一个简单的onTouch和o ...

  9. linux 编程 如何判断socket断开???--ongoing

    1 利用select ? 2从github上找例子 3 学习asio  c++ library

  10. TCP/IP学习笔记8--数据链路之基本概念

    "在你生命的最初30年中,你养成习惯:在你生命的最后30年中,你的习惯决定了你."---- Steve Jobs TCP/IP对于OSI参考模型的数据链路成及以下部分(物理层)没有 ...