SpringSecurity之授权
SpringSecurity之授权
1. 写在前面的话
此文并非教程, 而是个人学习SpringSecurity时的记录以及一些踩坑解决
如果能帮到大家, 那就让人非常开心了
另外, SpringSecurity的授权分为web授权和方法授权, 本文只说明了web授权, 方法授权实际上就是SpringSecurity控制对方法和接口的访问, 需要学习的小伙伴可以自行学习, 笔者在今后的工作中如果用到的话也会回来添加相关内容
好了, 让我们看看笔者的一些学习心得吧
2. web授权
个人认为授权较之认证简单了许多, 大概是本人在认证把该踩的坑都踩了一遍吧...
首先, 我们需要建立数据库
1. 建库
我们需要以下的几张表

角色表

权限表

用户表(这个在认证中已经建立了)

角色权限关联表 (此处为管理员有1和2两个权限)

用户角色关联表

- 关联表是为了方便拓展, 正常的业务都是这样的, 存在一对多和多对多的关系
2. 添加查询权限的接口
权限的信息也是存放在UserDetails中的, 因此我们也要实现通过用户id查询用户对应权限的功能
建立对应的实体类(此处省略)

添加接口以及其实现类
dao
//根据用户id查询用户权限
List<PermissionDTO> getPermissionByUserId(String userId);
service接口
List<PermissionDTO> getPermissionByUserId(String userId);
接口实现类
@Override
public List<PermissionDTO> getPermissionByUserId(String userId) {
return userMapper.getPermissionByUserId(userId);
}
在xml中添加查询的sql
<!--根据用户id查询用户权限-->
<select id="getPermissionByUserId" parameterType="string" resultType="permissionDTO">
select *
from t_permission
where `id` in (
select permission_id from t_role_permission
where role_id = (
select role_id from t_user_role
where user_id = #{userId}
)
)
</select>
- 注意, 这里我们使用了子查询, 同时, 由于会查出多条结果, 我们要酌情考虑是否要使用 in 语句, 将多个结果放在select语句的条件中
3. 前端页面的编写
我们使用的是 layui的默认后端模板
模板的定义
先编写一个后台模板文件
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<title>layout 后台大布局 - Layui</title>
<link rel="stylesheet" th:href="@{css/layui.css}">
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
<div class="layui-header">
<div class="layui-logo">layui 后台布局</div>
<!-- 头部区域(可配合layui已有的水平导航) -->
<ul class="layui-nav layui-layout-left">
<li class="layui-nav-item"><a href="">控制台</a></li>
<li class="layui-nav-item"><a href="">商品管理</a></li>
<li class="layui-nav-item"><a href="">用户</a></li>
<li class="layui-nav-item">
<a href="javascript:;">其它系统</a>
<dl class="layui-nav-child">
<dd><a href="">邮件管理</a></dd>
<dd><a href="">消息管理</a></dd>
<dd><a href="">授权管理</a></dd>
</dl>
</li>
</ul>
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:;">
<img src="http://t.cn/RCzsdCq" class="layui-nav-img">
<span sec:authentication="principal.username"></span>
</a>
<dl class="layui-nav-child">
<dd><a href="">基本资料</a></dd>
<dd><a href="">安全设置</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a id="logout" href="javascript:void(0);" onclick="logout()">退了</a></li>
</ul>
</div> <div class="layui-side layui-bg-black">
<div class="layui-side-scroll">
<!-- 左侧导航区域(可配合layui已有的垂直导航) -->
<ul class="layui-nav layui-nav-tree" lay-filter="test">
<li class="layui-nav-item layui-nav-itemed">
<a class="" href="javascript:;">所有商品</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">列表一</a></dd>
<dd><a href="javascript:;">列表二</a></dd>
<dd><a href="javascript:;">列表三</a></dd>
<dd><a href="">超链接</a></dd>
</dl>
</li>
<li class="layui-nav-item">
<a href="javascript:;">解决方案</a>
<dl class="layui-nav-child">
<dd><a href="javascript:;">列表一</a></dd>
<dd><a href="javascript:;">列表二</a></dd>
<dd><a href="">超链接</a></dd>
</dl>
</li>
<li class="layui-nav-item"><a href="">云市场</a></li>
<li class="layui-nav-item"><a href="">发布商品</a></li>
</ul>
</div>
</div> <!-- <div class="layui-body">-->
<!-- <!– 内容主体区域 –>-->
<!-- <div style="padding: 15px;">内容主体区域</div>-->
<!-- </div>--> <div class="layui-footer">
<!-- 底部固定区域 -->
layui.com - 底部固定区域
</div>
</div>
<script type="text/javascript" th:src="@{js/jquery.min.js}"></script>
<script type="text/javascript" th:src="@{js/jquery-ui.min.js}"></script>
<script type="text/javascript" th:src="@{js/jquery.mockjax.js}"></script>
<script th:src="@{layui.js}"></script>
<script>
//JavaScript代码区域
layui.use('element', function () {
var element = layui.element; }); function logout() {
layui.use('layer', function () {
//退出登录
layer.confirm('确定要退出么?', {icon: 3, title: '提示'}, function (index) {
//do something
let url = '/logout';
$.ajax({
url: url,
type: "post",
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function (data) {
alert("进入success---");
let code = data.code;
let url = data.url;
let msg = data.msg;
if (code == 203) {
alert(msg);
window.location.href = url;
} else {
alert("未知错误!");
}
},
error: function (xhr, textStatus, errorThrown) {
alert("进入error---");
alert("状态码:" + xhr.status);
alert("状态:" + xhr.readyState); //当前状态,0-未初始化,1-正在载入,2-已经载入,3-数据进行交互,4-完成。
alert("错误信息:" + xhr.statusText);
alert("返回响应信息:" + xhr.responseText);//这里是详细的信息
alert("请求状态:" + textStatus);
alert(errorThrown);
alert("请求失败");
}
});
layer.close(index);
});
});
}
</script>
</body>
</html>
- 注意
- 我们为了获得SpringSecurity中的用户名, 使用了SpringSecurity的thymeleaf方言, 可以实现细粒度的控制(依据权限是否显示某些标签)
- 引入命名空间, 这样就有代码提示了(不引入其实也无所谓~) xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
- 注意
测试用页面
为了测试权限, 我们定义了三个按钮, 分别对应三个权限(我们在下一节的SpringSecurity配置类中可以看到)
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>页面</title>
</head>
<body class="layui-layout-body"> <div th:include="content/layout"></div> <div class="layui-layout layui-layout-admin">
<div class="layui-body">
<!-- 内容主体区域 -->
<div style="padding: 15px;">成功应用模板!</div>
<div class="layui-btn-container">
<button type="button" class="layui-btn" onclick="btnClick1()">按钮一</button>
<button type="button" class="layui-btn" onclick="btnClick2()">按钮二</button>
<button type="button" class="layui-btn" onclick="btnClick3()">按钮三</button>
</div>
</div>
</div>
<script>
$.ajaxSetup({
type: "post",
dataType: "json",
contentType: "application/json;charset=utf-8",
success: function (data) {
let code = data.code;
let url = data.url;
let msg = data.msg;
if (code == 204) {
alert(msg);
window.location.href = url;
} else {
alert("未知错误!");
}
},
error: function (xhr, textStatus, errorThrown) {
alert("进入error---");
alert("状态码:" + xhr.status);
alert("状态:" + xhr.readyState); //当前状态,0-未初始化,1-正在载入,2-已经载入,3-数据进行交互,4-完成。
alert("错误信息:" + xhr.statusText);
alert("返回响应信息:" + xhr.responseText);//这里是详细的信息
alert("请求状态:" + textStatus);
alert(errorThrown);
alert("请求失败");
}
}); function btnClick1() {
let url = "/toR1";
$.ajax({
url: url,
type: "post",
dataType: "json",
contentType: "application/json;charset=utf-8", });
} function btnClick2() {
let url = "/toR2";
$.ajax({
url: url,
type: "post",
dataType: "json",
contentType: "application/json;charset=utf-8", });
} function btnClick3() {
let url = "/toR3";
$.ajax({
url: url,
type: "post",
dataType: "json",
contentType: "application/json;charset=utf-8", });
}
</script>
</body>
</html>
4. SpringSecurity配置
//授权
http
.authorizeRequests()
.antMatchers("/r/r1").hasAnyAuthority("p1")
.antMatchers("/r/r2").hasAnyAuthority("p2")
.antMatchers("/r/r3").access("hasAuthority('p1') and hasAuthority('p2')")
.antMatchers("/r/**").authenticated().anyRequest().permitAll();
在配置类中配置授权的规则
注意
- Authority和Role都是角色管理, 区别是Role会加一个 ROLE_ 前缀, 具体的区别可以在网上自行查看, 一般来说, 我们使用Authority就行了
5. Controller配置
- RestController处理AJAX
package com.wang.spring_security_framework.controller;
import com.alibaba.fastjson.JSON;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class RestfulJumpController {
@RequestMapping("/toR1")
public String toR1Page() {
String url = "/r/r1";
String code = "204";
String msg = "即将跳转!";
Map<String, String> resultMap = new HashMap<>();
resultMap.put("url", url);
resultMap.put("code", code);
resultMap.put("msg", msg);
return JSON.toJSONString(resultMap);
}
@RequestMapping("/toR2")
public String toR2Page() {
String url = "/r/r2";
String code = "204";
String msg = "即将跳转!";
Map<String, String> resultMap = new HashMap<>();
resultMap.put("url", url);
resultMap.put("code", code);
resultMap.put("msg", msg);
return JSON.toJSONString(resultMap);
}
@RequestMapping("/toR3")
public String toR3Page() {
String url = "/r/r3";
String code = "204";
String msg = "即将跳转!";
Map<String, String> resultMap = new HashMap<>();
resultMap.put("url", url);
resultMap.put("code", code);
resultMap.put("msg", msg);
return JSON.toJSONString(resultMap);
}
}
我们用RestController处理了Ajax的跳转请求, 并返回了JSON信息, 让前端进行url跳转
- 测试的授权Controller
这里的Controller用于显示对应的资源目录下的一些内容, 其中我们从会话中获取了当前登录的用户名
package com.wang.spring_security_framework.controller;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/r")
public class AuthorizeTestController {
//从会话中获取当前登录用户名
private String getUserName(){
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
//未登录, 返回null
if(!authentication.isAuthenticated()) {
return null;
}
Object principal = authentication.getPrincipal();
String username;
if (principal instanceof UserDetails) {
username = ((UserDetails) principal).getUsername();
} else {
username = principal.toString();
}
return username;
}
@RequestMapping("/r1")
public String R1() {
return getUserName() + "访问资源1";
}
@RequestMapping("/r2")
public String R2() {
return getUserName() + "访问资源2";
}
@RequestMapping("/r3")
public String R3() {
return getUserName() + "访问资源3";
}
}
3. 结语
本篇看起来很简单, 事实上也确实很简单......
主要需要理解的是数据库的建立以及关联表的处理, 其中的SQL语句才是最难搞的
访问没有授权的页面, 会爆出 405 错误, 我们可以自定义错误页面来处理这种错误(此处就不叙述了, 属于SpringBoot的内容~)
欢迎小伙伴批评与交流~
SpringSecurity之授权的更多相关文章
- 使用SpringSecurity搭建授权认证服务(1) -- 基本demo认证原理
使用SpringSecurity搭建授权认证服务(1) -- 基本demo 登录认证是做后台开发的最基本的能力,初学就知道一个interceptor或者filter拦截所有请求,然后判断参数是否合理, ...
- SpringBoot--- 使用SpringSecurity进行授权认证
SpringBoot--- 使用SpringSecurity进行授权认证 前言 在未接触 SpringSecurity .Shiro 等安全认证框架之前,如果有页面权限需求需要满足,通常可以用拦截器, ...
- [原创]SpringSecurity控制授权(鉴权)功能介绍
1.spring security 过滤器链 spring security中的除了用户登录校验相关的过滤器,最后还包含了鉴权功能的过滤器,还有匿名资源访问的过滤器链,相关的图解如下: 2.控制授 ...
- springsecurity4+springboot 实现remember-me 发现springsecurity 的BUG
前言:现在开发中,记住我这个功能是普遍的,用户不可能每次登录都要输入用户名密码.昨天准备用spring security的记住我功能,各种坑啊,吐血 . 先看下具体实现吧. spring securi ...
- SpringBoot19 集成SpringSecurity01 -> 环境搭建、SpringSecurity验证
1 环境搭建 1.1 创建一个SpringBoot项目 项目脚手架 -> 点击前往 1.2 创建一个Restful接口 新建一个Controller类即可 package com.example ...
- spring-security实现的token授权
在我的用户密码授权文章里介绍了spring-security的工作过程,不了解的同学,可以先看看用户密码授权这篇文章,在 用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到sessi ...
- 基于SpringSecurity和JWT的用户访问认证和授权
发布时间:2018-12-03 技术:springsecurity+jwt+java+jpa+mysql+mysql workBench 概述 基于SpringSecurity和JWT的用户访 ...
- SpringSecurity04 利用JPA和SpringSecurity实现前后端分离的认证和授权
1 环境搭建 1.1 环境说明 JDK:1.8 MAVEN:3.5 SpringBoot:2.0.4 SpringSecurity:5.0.7 IDEA:2017.02旗舰版 1.2 环境搭建 创建一 ...
- SpringBoot+SpringSecurity之多模块用户认证授权同步
在之前的文章里介绍了SpringBoot和SpringSecurity如何继承.之后我们需要考虑另外一个问题:当前微服务化也已经是大型网站的趋势,当我们的项目采用微服务化架构时,往往会出现如下情况: ...
随机推荐
- ubuntu 搭建samba服务器&挂载(mount)代码到本地
一.搭建samba服务器 1.下载: sudo apt-get install samba samba-common 2.创建共享文件夹MyShare: mkdir /home/user/MyShar ...
- django—csrf中间件校验流程
CSRF(跨站请求伪造)是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的攻击方法. 这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求 ...
- Python ( 学习 基础篇第一部 )
目录 注释 注释的分类 注释的注意点 变量 变量的概念 变量的声明 变量的命名 变量的交换 变量的缓存机制 常量 进制 进制的转换 原码 反码 补码 六大数据类型 Number 的四大类 字符串 st ...
- 动态规划专题一:线性dp
第一篇博客随笔,被迫写的bushi 上课讲的动态规划入门,还是得总结一下吧 背包 01背包 背包有容量限制,每一件物品只能够取一件(这就是为什么j从V至v[i]循环的原因) 思路:f数组表示当前状态的 ...
- git的远程分支是干啥的,和本地的有什么区别?
不知道大家有没有经历过,当我们切换到了一个新的分支想要提交代码的时候,总会遇到这样的错误. 我们把日志里的英文翻译过来是说,我们当前的分支没有设置任何上游分支.然后git提示我们可以运行下面这行代码来 ...
- 测试可变字符序列stringBuilder
测试可变字符序列 stringBuilder(线程不安全,效率高,一般用),stringBuffer(线程安全,效率低)stringBuilder,stringBuffer和string的区别前者可变 ...
- NB-IOT覆盖能力有多强 是怎么实现的
NB-IoT技术中出现以来就以其强大的覆盖能力和通信距离长而受到广大使用者的欢迎,那么NB-IoT覆盖能力究竟是有多大,其覆盖能力应该怎么来衡量? 强大的覆盖能力是NB-IoT技术的最大特点之一,不仅 ...
- SpringBoot第四集:静态资源与首页定(2020最新最易懂)
SpringBoot第四集:静态资源与首页定(2020最新最易懂) 问题 SpringBoot构建的项目结构如下:没有webapp目录,没有WEB-INF等目录,那么如果开发web项目,项目资源放在那 ...
- python用scrapy模拟用户登录
scrapy模拟登录 关注公众号"轻松学编程"了解更多. 注意:模拟登陆时,必须保证settings.py里的COOKIES_ENABLED(Cookies中间件) 处于开启状态 ...
- python创建Django项目
创建Django项目 关注公众号"轻松学编程"了解更多. 创建一个HelloDjango项目 GitHub地址:https://github.com/liangdongchang/ ...