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如何继承.之后我们需要考虑另外一个问题:当前微服务化也已经是大型网站的趋势,当我们的项目采用微服务化架构时,往往会出现如下情况: ...
随机推荐
- 【Azure Developer】使用.Net Core解析JSON的笔记
在C#中解析JSON的一些历史代码记录,分别记录针对各种情况的解析方式. DLL的引用 using Newtonsoft.Json; using Newtonsoft.Json.Linq; 需要使用的 ...
- liunx 免密登录远程主机
#!/bin/bash #Program: # no password login in hosts #History: # hbl 2017/12/9 1.0.0v function auto-lo ...
- servlet post response.sendRedirect 乱码
response.sendRedircet一般用于传递字符串参数 常会出现乱码: 情景1: post表单提交,跳转后的servlet,通过getParameter(name)进行解码,获取的中文乱码 ...
- ssm整合之web.xml文件
<!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" " ...
- etc/river.toml
# MySQL address, user and password # user must have replication privilege in MySQL. my_addr = " ...
- Cloudera Manager简介
Hadoop家族 整个Hadoop家族由以下几个子项目组成: Hadoop Common: Hadoop体系最底层的一个模块,为Hadoop各子项目提供各 种工具,如:配置文件和日志操作等. HDFS ...
- xml在spring中
平时用的最多的框架莫过Spring,但就算用了怎么久也一直对Spring配置文件的头部那一堆的XML Schema云里雾里的. 今天就来好好整整.俗话说,岁月是把杀猪刀,说不定哪天又忘了,好记性不如烂 ...
- Excel基础—为什么学习Excel
吾生也有涯,而知也无涯 点赞再看,养成习惯 自从个人计算机开始普及以后,Excel就得到了广泛的传播,工作学习生活中不处不存在Excel的影子,不论是考勤,工资还是其他的统计等等,都离不开Excel. ...
- .netcore 自定义多种身份验证方法混用
背景: 公司项目有很多租户,每个租户的系统都可能调用我们的租户服务,原来的解决方案是为每个租户提供一个service.随着租户的增多,service也多了起来,但是每个service里的逻辑都是一样的 ...
- insert into select 和select into from 备份表
一 insert into select要求表必须存在 INSERTINTO order_record SELECT * FROM order_today FORCEINDEX (idx_pay_su ...