SpringBoot&Shiro实现用户认证
SpringBoot&Shiro实现用户认证
实现思路
思路:实现认证功能主要可以归纳为3点
1.定义一个ShiroConfig配置类,配置 SecurityManager Bean , SecurityManager为Shiro的安全管理器,管理着所有Subject;
注:如果有不太清楚shiro的朋友,可以去各大学习平台上学习一下。
2.在ShiroConfig中配置 ShiroFilterFactoryBean ,它是Shiro过滤器工厂类,依赖SecurityManager ;
3.自定义Realm实现类,包含
doGetAuthorizationInfo()和doGetAuthenticationInfo()方法 ,
1.导入依赖
我们搭建好Spring Boot web程序后,导入Shiro,Mybatis,mysql, thymeleaf 相关依赖:
<!-- SpringBoot Web容器 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- SpringBoot集成mybatis框架 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!-- SpringBoot 测试 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- thymeleaf模版 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- mysql驱动7.0-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<!--druid 数据源监控-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency>
<!-- shiro权限 -->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
2.定义ShiroConfig配置类:
/**
* @ClassName ShiroConfig
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:08
* @Version 1.0
*/
@Configuration
public class ShiroConfig {
/**
* 这是shiro的大管家,相当于mybatis里的SqlSessionFactoryBean
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilterFactoryBean(org.apache.shiro.mgt.SecurityManager securityManager) {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
//登录
shiroFilterFactoryBean.setLoginUrl("/login");
//首页
shiroFilterFactoryBean.setSuccessUrl("/index");
//错误页面,认证不通过跳转
shiroFilterFactoryBean.setUnauthorizedUrl("/403");
//页面权限控制
shiroFilterFactoryBean.setFilterChainDefinitionMap(ShiroFilterMapFactory.shiroFilterMap());
//设置securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager);
return shiroFilterFactoryBean;
}
/**
* web应用管理配置
* @param shiroRealm
* @return
*/
@Bean
public DefaultWebSecurityManager securityManager(Realm shiroRealm) {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm);
return securityManager;
}
/**
* 配置realm,用于认证和授权
* @return
*/
@Bean
public MyShiroRealm shiroRealm() {
MyShiroRealm shiroRealm = new MyShiroRealm();
return shiroRealm;
}
}
3.创建ShiroFilterMapFactory类
注意:
1.这里要用LinkedHashMap 保证有序
2.filterChain基于短路机制,即最先匹配原则,
3.像anon、authc等都是Shiro为我们实现的过滤器,我给出了一张表,在文章尾附录,自行查看
/**
* @ClassName ShiroFilterMapFactory
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:09
* @Version 1.0
*/
public class ShiroFilterMapFactory {
public static Map<String, String> shiroFilterMap() {
// 设置路径映射,注意这里要用LinkedHashMap 保证有序
LinkedHashMap<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//对所有用户认证
filterChainDefinitionMap.put("/static/**", "anon");
filterChainDefinitionMap.put("/login", "anon");
filterChainDefinitionMap.put("/logout", "logout");
//对所有页面进行认证
filterChainDefinitionMap.put("/**", "authc");
return filterChainDefinitionMap;
}
}
配置完了ShiroConfig后,实现自己的Realm,然后注入到SecurityManager里
4.实现Realm类
自定义Realm类需要继承 AuthorizingRealm 类,实现 doGetAuthorizationInfo()和doGetAuthenticationInfo()方法即可 ,
doGetAuthorizationInfo() 方法是进行授权的方法,获取角色的权限信息
doGetAuthenticationInfo()方法是进行用户认证的方法,验证用户名和密码
/**
* @ClassName MyShiroRealm
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:08
* @Version 1.0
*/
@Service
public class MyShiroRealm extends AuthorizingRealm {
@Autowired
private UserMapper userMapper;
/**
* 获取用户角色和权限
* @param principalCollection
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
return null;
}
/**
* 登录认证
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
//获取用户输入的用户名密码
String username= (String) token.getPrincipal();
String password=new String((char[])token.getCredentials());
System.out.println("用户输入--->username:"+username+"-->password:"+password);
//在数据库中查询
User userInfo=userMapper.selectByName(username);
if (userInfo == null) {
throw new UnknownAccountException("用户名或密码错误!");
}
if (!password.equals(userInfo.getPassword())) {
throw new IncorrectCredentialsException("用户名或密码错误!");
}
SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
userInfo, // 用户名
userInfo.getPassword(), // 密码
getName() // realm name
);
return authenticationInfo;
}
}
doGetAuthorizationInfo()方法我们留到下一章实现,其中UnknownAccountException等异常为Shiro自带异常,Shiro具有丰富的运行时AuthenticationException层次结构,可以准确指出尝试失败的原因。
接下来我们实现dao层!
4.数据层
数据表设计的比较简单,方便操作
CREATE TABLE `tb_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_bin DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 2 CHARACTER SET = utf8 COLLATE = utf8_bin ROW_FORMAT = Compact;
然后创建一张对应的用户表User.class
public class User implements Serializable {
private Integer id;
private String username;
private String password;
....get和set方法省略
}
定义接口UserMapper
这里用的是注解
/**
* @ClassName UserMapper
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 3:30
* @Version 1.0
*/
public interface UserMapper {
@Select("select * from tb_user where username=#{username}")
User selectByName(String username);
}
注意:记得在Mapper接口上面加一个扫描注解@Mapper或者在boot启动类上加一个@MapperScan(value = "mapper包路径")注解
5.控制层
我们创建一个LoginController.class类
/**
* @ClassName LoginController
* @Description TODO
* @Author fqCoder
* @Date 2020/2/29 6:06
* @Version 1.0
*/
@Controller
public class LoginController {
@GetMapping("/login")
public String login(){
return "login";
}
@GetMapping("/")
public String home(){
return "redirect:/index";
}
@GetMapping("/index")
public String index(Model model){
User user= (User) SecurityUtils.getSubject().getPrincipal();
model.addAttribute("user",user);
return "index";
}
@PostMapping("login")
@ResponseBody
public AjaxResult login(User user){
System.out.println("user = " + user);
UsernamePasswordToken token = new UsernamePasswordToken(user.getUsername(), user.getPassword());
//获取Subject 对象
Subject subject= SecurityUtils.getSubject();
try {
subject.login(token);
return AjaxResult.success("/index");
} catch (UnknownAccountException e) {
return AjaxResult.error(e.getMessage());
} catch (IncorrectCredentialsException e) {
return AjaxResult.error(e.getMessage());
}
}
}
6.登录页面
编写login.html页面
这里我只贴重要代码,具体的代码,到github里找哦!
<form id="loginForm">
<input type="text" id="username" name="username" class="text" />
<input type="password" id="password" name="password" />
</form>
<div class="signin">
<input id="loginBut" type="button" value="Login" >
</div>
-------js代码----
<script type="text/javascript">
$.fn.serializeObject = function () {
var o = {};
var a = this.serializeArray();
$.each(a, function () {
if (o[this.name]) {
if (!o[this.name].push) {
o[this.name] = [o[this.name]];
}
o[this.name].push(this.value);
} else {
o[this.name] = this.value || '';
}
});
return o;
};
$(function () {
$("#loginBut").click(function () {
var arr=$('#loginForm').serializeObject();
$.ajax({
url: '/login',
type: 'post',
data: arr,
dataType: "json",
success: function (data) {
if (data.code==200){
location.href=data.msg;
} else {
alert(data.msg);
}
},
error: function (data) {
alert(data.msg);
}
})
});
});
</script>
7.启动
先看一下目录

启动项目:访问http://localhost:8080/,它会自动拦截,页面重定向到 http://localhost:8080/login
总结:
SpringBoot整合Shiro实现用户认证功能就到此结束了,一些细节代码参见 https://github.com/Slags/springboot-learn/tree/master/1.springboot-shiro-authentication
附录:
1.Shiro拦截机制表
| Filter Name | Class | Description |
|---|---|---|
| anon | org.apache.shiro.web.filter.authc.AnonymousFilter | 匿名拦截器,即不需要登录即可访问;一般用于静态资源过滤;示例/static/**=anon |
| authc | org.apache.shiro.web.filter.authc.FormAuthenticationFilter | 基于表单的拦截器;如/**=authc,如果没有登录会跳到相应的登录页面登录 |
| authcBasic | org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter | Basic HTTP身份验证拦截器 |
| logout | org.apache.shiro.web.filter.authc.LogoutFilter | 退出拦截器,主要属性:redirectUrl:退出成功后重定向的地址(/),示例/logout=logout |
| noSessionCreation | org.apache.shiro.web.filter.session.NoSessionCreationFilter | 不创建会话拦截器,调用subject.getSession(false)不会有什么问题,但是如果subject.getSession(true)将抛出DisabledSessionException异常 |
| perms | org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter | 权限授权拦截器,验证用户是否拥有所有权限;属性和roles一样;示例/user/**=perms["user:create"] |
| port | org.apache.shiro.web.filter.authz.PortFilter | 端口拦截器,主要属性port(80):可以通过的端口;示例/test= port[80],如果用户访问该页面是非80,将自动将请求端口改为80并重定向到该80端口,其他路径/参数等都一样 |
| rest | org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter | rest风格拦截器,自动根据请求方法构建权限字符串;示例/users=rest[user],会自动拼出user:read,user:create,user:update,user:delete权限字符串进行权限匹配(所有都得匹配,isPermittedAll) |
| roles | org.apache.shiro.web.filter.authz.RolesAuthorizationFilter | 角色授权拦截器,验证用户是否拥有所有角色;示例/admin/**=roles[admin] |
| ssl | org.apache.shiro.web.filter.authz.SslFilter | SSL拦截器,只有请求协议是https才能通过;否则自动跳转会https端口443;其他和port拦截器一样; |
| user | org.apache.shiro.web.filter.authc.UserFilter | 用户拦截器,用户已经身份验证/记住我登录的都可;示例/**=user |
SpringBoot&Shiro实现用户认证的更多相关文章
- 项目一:第十一天 2、运单waybill快速录入 3、权限demo演示-了解 5、权限模块数据模型 6、基于shiro实现用户认证-登录(重点)
1. easyui DataGrid行编辑功能 2. 运单waybill快速录入 3. 权限demo演示-了解 4. Apache shiro安全框架概述 5. 权限模块数据模型 6. 基于shiro ...
- Spring Cloud之路:(七)SpringBoot+Shiro实现登录认证和权限管理
版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/sage_wang/article/details/79592269一.Shiro介绍1.Shiro是 ...
- springboot shiro和freemarker集成之权限控制完全参考手册(跳过认证,登录由三方验证,全网首发)
本文主要考虑单点登录场景,登录由其他系统负责,业务子系统只使用shiro进行菜单和功能权限校验,登录信息通过token从redis取得,这样登录验证和授权就相互解耦了. 用户.角色.权限进行集中式管理 ...
- spring-boot整合shiro作权限认证
spring-shiro属于轻量级权限框架,即使spring-security更新换代,市场上大多数企业还是选择shiro 废话不多说 引入pom文件 <!--shiro集成spring--& ...
- springboot集成shiro实现权限认证
github:https://github.com/peterowang/shiro 基于上一篇:springboot集成shiro实现身份认证 1.加入UserController package ...
- springboot系列(十)springboot整合shiro实现登录认证
关于shiro的概念和知识本篇不做详细介绍,但是shiro的概念还是需要做做功课的要不无法理解它的运作原理就无法理解使用shiro: 本篇主要讲解如何使用shiro实现登录认证,下篇讲解使用shiro ...
- 用户认证授权和Shiro入门
1.权限管理基础(认证和授权): 前言 本文主要讲解的知识点有以下: 权限管理的基础知识 模型 粗粒度和细粒度的概念 回顾URL拦截的实现 Shiro的介绍与简单入门 一.Shiro基础知识 在学习S ...
- springboot集成shiro实现身份认证
github地址:https://github.com/peterowang/shiro pom文件 <dependencies> <dependency> <group ...
- SpringBoot+SpringSecurity之多模块用户认证授权同步
在之前的文章里介绍了SpringBoot和SpringSecurity如何继承.之后我们需要考虑另外一个问题:当前微服务化也已经是大型网站的趋势,当我们的项目采用微服务化架构时,往往会出现如下情况: ...
随机推荐
- C3D使用指南
C3D GitHub项目地址:https://github.com/facebook/C3D C3D 官方用户指南:https://goo.gl/k2SnLY 1. C3D特征提取 1.1 命令参数介 ...
- NLP-文本分类之开始(0)
转眼读研一年了,开题也开了,方向也定了,大方向就是NLP,然而从一开始的上课.做项目开题什么的(自己也比较贪玩,以前不打游戏,结果王者上瘾了),到现在对NLP是一知半解,不对,半解都没有半解,然后时间 ...
- TOJ-3474 The Big Dance(递归二分)
链接:https://ac.nowcoder.com/acm/contest/1077/L 题目描述 Bessie and the herd, N (1 <= N <= 2,200) co ...
- 求最近公共祖先(LCA)的各种算法
水一发题解. 我只是想存一下树剖LCA的代码...... 以洛谷上的这个模板为例:P3379 [模板]最近公共祖先(LCA) 1.朴素LCA 就像做模拟题一样,先dfs找到基本信息:每个节点的父亲.深 ...
- day46-守护线程
#1.守护线程要注意的坑:下面代码只能打印出子线程开始,无法打印出子线程执行完毕,因为主线程在t.start()以后就结束了, #而子线程要睡眠1秒,所以子线程守护线程随着主线程的结束而结束了. fr ...
- gene cluster|DPG|拉马克主义变异|达尔文主义变异
生命组学 A gene cluster is part of a gene family. A gene cluster is a group of two or more genes found w ...
- python-django-fastdfs+Nginx的安装和配置_20191122
python-django-fastdfs+Nginx的安装和配置 FastDFS文件系统 FastDFS文件系统简介: 是c语言编写的,是淘宝的架构师写的,存储淘宝的图片,后来开源了, fastDF ...
- python中字典以key排序,以value排序。以及通过value找key的方式
1.sorted函数首先介绍sorted函数,sorted(iterable,key,reverse),sorted一共有iterable,key,reverse这三个参数. 其中iterable表示 ...
- java和javac命令
记录一下,今天无意中用到单独编译和执行某个java类,遇到各种Error: Could not find or load main class等问题,解决方案如下其中2和3选其一试试~ 1.javac ...
- Angular开发者指南(五)服务
服务 AngularJS服务是使用依赖注入(DI)连接在一起的可替代对象. 可以使用服务在整个应用程式中整理和分享程式码. AngularJS服务有: 延迟初始化 - AngularJS只在应用程序组 ...