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如何继承.之后我们需要考虑另外一个问题:当前微服务化也已经是大型网站的趋势,当我们的项目采用微服务化架构时,往往会出现如下情况: ...
随机推荐
- Linux命令之Hash缓存表
Hash缓存表 系统初始hash表为空,当外部命令执行时,默认会从PATH路径下寻找该命令,找到后会将这条命令的路径记录到hash表中,当再次使用该命令时,shell解释器首先会查看hash表,存在将 ...
- npm install各种命令模式
npm install 几种命令模式: npm install moduleName 安装模块到项目目录下 npm install -g moduleName npm install -g 将模块安装 ...
- spring与struts2整合出现错误HTTP Status 500 - Unable to instantiate Action
在进行spring和struts2整合的时候因为大意遇到了一个问题,费了半天神终于找到了问题所在,故分享出来望广大博友引以为戒!! 我们都知道在spring和struts2整合时,spring接管了a ...
- 学python,大概要多久?
都让开!本人文科生,自学Python 2年半,作为一个曾经完全0基础,啥都不懂纯靠自学学会python的文科生,有一些不成熟的小建议可以分享一下. 首先不要觉着编程难,只要你认识26个英文字母,有一点 ...
- forword与redirect
1.从地址栏显示来说 forward是服务器请求资源,服务器直接访问目标地址的URL,把那个URL的响应内容读取过来,然后把这些内容再发给浏览器.浏览器根本不知道服务器发送的内容从哪里来的,所以它的地 ...
- toolbox docker国内镜像(阿里云加速器)
docker-machine create --engine-registry-mirror=加速地址 -d virtualbox default# 若虚拟机已经创建好docker-machine s ...
- Mongodb命令 --- MongoDB基础用法(二)
Mongodb命令 数据库操作 创建数据库 MongoDB 创建数据库的语法格式如下: use DATABASE_NAME 如果数据库不存在,则创建数据库,否则切换到指定数据库. 删除数据库 Mong ...
- StrongArray
* System类中包含了一个static void arraycopy(object src,int srcops,object dest ,int destpos, int length )方法, ...
- Flutter 1.22版本新增的Button
Flutter 1.22版本新增了3个按钮,TextButton.OutlinedButton.ElevatedButton,虽然以前的Button没有被废弃,但还是建议使用新的Button. 为什么 ...
- SpringBoot 构建 Docker 镜像的最佳 3 种方式
本文将介绍3种技术,通过 Maven 把 SpringBoot 应用构建成 Docker 镜像. (1)使用 spring-boot-maven-plugin 内置的 build-image. (2) ...