SpringSecurity之授权

1. 写在前面的话

此文并非教程, 而是个人学习SpringSecurity时的记录以及一些踩坑解决

如果能帮到大家, 那就让人非常开心了

另外, SpringSecurity的授权分为web授权和方法授权, 本文只说明了web授权, 方法授权实际上就是SpringSecurity控制对方法和接口的访问, 需要学习的小伙伴可以自行学习, 笔者在今后的工作中如果用到的话也会回来添加相关内容

好了, 让我们看看笔者的一些学习心得吧

2. web授权

个人认为授权较之认证简单了许多, 大概是本人在认证把该踩的坑都踩了一遍吧...

首先, 我们需要建立数据库

1. 建库

我们需要以下的几张表

  • 角色表

  • 权限表

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

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

  • 用户角色关联表

    • 关联表是为了方便拓展, 正常的业务都是这样的, 存在一对多和多对多的关系

2. 添加查询权限的接口

权限的信息也是存放在UserDetails中的, 因此我们也要实现通过用户id查询用户对应权限的功能

  • 建立对应的实体类(此处省略)

  • 添加接口以及其实现类

    • dao

      1. //根据用户id查询用户权限
      2. List<PermissionDTO> getPermissionByUserId(String userId);
    • service接口

      1. List<PermissionDTO> getPermissionByUserId(String userId);
    • 接口实现类

      1. @Override
      2. public List<PermissionDTO> getPermissionByUserId(String userId) {
      3. return userMapper.getPermissionByUserId(userId);
      4. }
  • 在xml中添加查询的sql

    1. <!--根据用户id查询用户权限-->
    2. <select id="getPermissionByUserId" parameterType="string" resultType="permissionDTO">
    3. select *
    4. from t_permission
    5. where `id` in (
    6. select permission_id from t_role_permission
    7. where role_id = (
    8. select role_id from t_user_role
    9. where user_id = #{userId}
    10. )
    11. )
    12. </select>
    • 注意, 这里我们使用了子查询, 同时, 由于会查出多条结果, 我们要酌情考虑是否要使用 in 语句, 将多个结果放在select语句的条件中

3. 前端页面的编写

我们使用的是 layui的默认后端模板

  • 模板的定义

    先编写一个后台模板文件

    1. <!DOCTYPE html>
    2. <html xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/extras/spring-security">
    3. <head>
    4. <meta charset="utf-8">
    5. <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    6. <title>layout 后台大布局 - Layui</title>
    7. <link rel="stylesheet" th:href="@{css/layui.css}">
    8. </head>
    9. <body class="layui-layout-body">
    10. <div class="layui-layout layui-layout-admin">
    11. <div class="layui-header">
    12. <div class="layui-logo">layui 后台布局</div>
    13. <!-- 头部区域(可配合layui已有的水平导航) -->
    14. <ul class="layui-nav layui-layout-left">
    15. <li class="layui-nav-item"><a href="">控制台</a></li>
    16. <li class="layui-nav-item"><a href="">商品管理</a></li>
    17. <li class="layui-nav-item"><a href="">用户</a></li>
    18. <li class="layui-nav-item">
    19. <a href="javascript:;">其它系统</a>
    20. <dl class="layui-nav-child">
    21. <dd><a href="">邮件管理</a></dd>
    22. <dd><a href="">消息管理</a></dd>
    23. <dd><a href="">授权管理</a></dd>
    24. </dl>
    25. </li>
    26. </ul>
    27. <ul class="layui-nav layui-layout-right">
    28. <li class="layui-nav-item">
    29. <a href="javascript:;">
    30. <img src="http://t.cn/RCzsdCq" class="layui-nav-img">
    31. <span sec:authentication="principal.username"></span>
    32. </a>
    33. <dl class="layui-nav-child">
    34. <dd><a href="">基本资料</a></dd>
    35. <dd><a href="">安全设置</a></dd>
    36. </dl>
    37. </li>
    38. <li class="layui-nav-item"><a id="logout" href="javascript:void(0);" onclick="logout()">退了</a></li>
    39. </ul>
    40. </div>
    41. <div class="layui-side layui-bg-black">
    42. <div class="layui-side-scroll">
    43. <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
    44. <ul class="layui-nav layui-nav-tree" lay-filter="test">
    45. <li class="layui-nav-item layui-nav-itemed">
    46. <a class="" href="javascript:;">所有商品</a>
    47. <dl class="layui-nav-child">
    48. <dd><a href="javascript:;">列表一</a></dd>
    49. <dd><a href="javascript:;">列表二</a></dd>
    50. <dd><a href="javascript:;">列表三</a></dd>
    51. <dd><a href="">超链接</a></dd>
    52. </dl>
    53. </li>
    54. <li class="layui-nav-item">
    55. <a href="javascript:;">解决方案</a>
    56. <dl class="layui-nav-child">
    57. <dd><a href="javascript:;">列表一</a></dd>
    58. <dd><a href="javascript:;">列表二</a></dd>
    59. <dd><a href="">超链接</a></dd>
    60. </dl>
    61. </li>
    62. <li class="layui-nav-item"><a href="">云市场</a></li>
    63. <li class="layui-nav-item"><a href="">发布商品</a></li>
    64. </ul>
    65. </div>
    66. </div>
    67. <!-- <div class="layui-body">-->
    68. <!-- &lt;!&ndash; 内容主体区域 &ndash;&gt;-->
    69. <!-- <div style="padding: 15px;">内容主体区域</div>-->
    70. <!-- </div>-->
    71. <div class="layui-footer">
    72. <!-- 底部固定区域 -->
    73. layui.com - 底部固定区域
    74. </div>
    75. </div>
    76. <script type="text/javascript" th:src="@{js/jquery.min.js}"></script>
    77. <script type="text/javascript" th:src="@{js/jquery-ui.min.js}"></script>
    78. <script type="text/javascript" th:src="@{js/jquery.mockjax.js}"></script>
    79. <script th:src="@{layui.js}"></script>
    80. <script>
    81. //JavaScript代码区域
    82. layui.use('element', function () {
    83. var element = layui.element;
    84. });
    85. function logout() {
    86. layui.use('layer', function () {
    87. //退出登录
    88. layer.confirm('确定要退出么?', {icon: 3, title: '提示'}, function (index) {
    89. //do something
    90. let url = '/logout';
    91. $.ajax({
    92. url: url,
    93. type: "post",
    94. dataType: "json",
    95. contentType: "application/json;charset=utf-8",
    96. success: function (data) {
    97. alert("进入success---");
    98. let code = data.code;
    99. let url = data.url;
    100. let msg = data.msg;
    101. if (code == 203) {
    102. alert(msg);
    103. window.location.href = url;
    104. } else {
    105. alert("未知错误!");
    106. }
    107. },
    108. error: function (xhr, textStatus, errorThrown) {
    109. alert("进入error---");
    110. alert("状态码:" + xhr.status);
    111. alert("状态:" + xhr.readyState); //当前状态,0-未初始化,1-正在载入,2-已经载入,3-数据进行交互,4-完成。
    112. alert("错误信息:" + xhr.statusText);
    113. alert("返回响应信息:" + xhr.responseText);//这里是详细的信息
    114. alert("请求状态:" + textStatus);
    115. alert(errorThrown);
    116. alert("请求失败");
    117. }
    118. });
    119. layer.close(index);
    120. });
    121. });
    122. }
    123. </script>
    124. </body>
    125. </html>
    • 注意

      • 我们为了获得SpringSecurity中的用户名, 使用了SpringSecurity的thymeleaf方言, 可以实现细粒度的控制(依据权限是否显示某些标签)
      • 引入命名空间, 这样就有代码提示了(不引入其实也无所谓~) xmlns:sec="http://www.thymeleaf.org/extras/spring-security"
  • 测试用页面

    为了测试权限, 我们定义了三个按钮, 分别对应三个权限(我们在下一节的SpringSecurity配置类中可以看到)

    1. <!DOCTYPE html>
    2. <html lang="en" xmlns:th="http://www.thymeleaf.org">
    3. <head>
    4. <meta charset="UTF-8">
    5. <title>页面</title>
    6. </head>
    7. <body class="layui-layout-body">
    8. <div th:include="content/layout"></div>
    9. <div class="layui-layout layui-layout-admin">
    10. <div class="layui-body">
    11. <!-- 内容主体区域 -->
    12. <div style="padding: 15px;">成功应用模板!</div>
    13. <div class="layui-btn-container">
    14. <button type="button" class="layui-btn" onclick="btnClick1()">按钮一</button>
    15. <button type="button" class="layui-btn" onclick="btnClick2()">按钮二</button>
    16. <button type="button" class="layui-btn" onclick="btnClick3()">按钮三</button>
    17. </div>
    18. </div>
    19. </div>
    20. <script>
    21. $.ajaxSetup({
    22. type: "post",
    23. dataType: "json",
    24. contentType: "application/json;charset=utf-8",
    25. success: function (data) {
    26. let code = data.code;
    27. let url = data.url;
    28. let msg = data.msg;
    29. if (code == 204) {
    30. alert(msg);
    31. window.location.href = url;
    32. } else {
    33. alert("未知错误!");
    34. }
    35. },
    36. error: function (xhr, textStatus, errorThrown) {
    37. alert("进入error---");
    38. alert("状态码:" + xhr.status);
    39. alert("状态:" + xhr.readyState); //当前状态,0-未初始化,1-正在载入,2-已经载入,3-数据进行交互,4-完成。
    40. alert("错误信息:" + xhr.statusText);
    41. alert("返回响应信息:" + xhr.responseText);//这里是详细的信息
    42. alert("请求状态:" + textStatus);
    43. alert(errorThrown);
    44. alert("请求失败");
    45. }
    46. });
    47. function btnClick1() {
    48. let url = "/toR1";
    49. $.ajax({
    50. url: url,
    51. type: "post",
    52. dataType: "json",
    53. contentType: "application/json;charset=utf-8",
    54. });
    55. }
    56. function btnClick2() {
    57. let url = "/toR2";
    58. $.ajax({
    59. url: url,
    60. type: "post",
    61. dataType: "json",
    62. contentType: "application/json;charset=utf-8",
    63. });
    64. }
    65. function btnClick3() {
    66. let url = "/toR3";
    67. $.ajax({
    68. url: url,
    69. type: "post",
    70. dataType: "json",
    71. contentType: "application/json;charset=utf-8",
    72. });
    73. }
    74. </script>
    75. </body>
    76. </html>

4. SpringSecurity配置

  1. //授权
  2. http
  3. .authorizeRequests()
  4. .antMatchers("/r/r1").hasAnyAuthority("p1")
  5. .antMatchers("/r/r2").hasAnyAuthority("p2")
  6. .antMatchers("/r/r3").access("hasAuthority('p1') and hasAuthority('p2')")
  7. .antMatchers("/r/**").authenticated().anyRequest().permitAll();

在配置类中配置授权的规则

注意

  • Authority和Role都是角色管理, 区别是Role会加一个 ROLE_ 前缀, 具体的区别可以在网上自行查看, 一般来说, 我们使用Authority就行了

5. Controller配置

  • RestController处理AJAX
  1. package com.wang.spring_security_framework.controller;
  2. import com.alibaba.fastjson.JSON;
  3. import org.springframework.web.bind.annotation.RequestMapping;
  4. import org.springframework.web.bind.annotation.RestController;
  5. import java.util.HashMap;
  6. import java.util.Map;
  7. @RestController
  8. public class RestfulJumpController {
  9. @RequestMapping("/toR1")
  10. public String toR1Page() {
  11. String url = "/r/r1";
  12. String code = "204";
  13. String msg = "即将跳转!";
  14. Map<String, String> resultMap = new HashMap<>();
  15. resultMap.put("url", url);
  16. resultMap.put("code", code);
  17. resultMap.put("msg", msg);
  18. return JSON.toJSONString(resultMap);
  19. }
  20. @RequestMapping("/toR2")
  21. public String toR2Page() {
  22. String url = "/r/r2";
  23. String code = "204";
  24. String msg = "即将跳转!";
  25. Map<String, String> resultMap = new HashMap<>();
  26. resultMap.put("url", url);
  27. resultMap.put("code", code);
  28. resultMap.put("msg", msg);
  29. return JSON.toJSONString(resultMap);
  30. }
  31. @RequestMapping("/toR3")
  32. public String toR3Page() {
  33. String url = "/r/r3";
  34. String code = "204";
  35. String msg = "即将跳转!";
  36. Map<String, String> resultMap = new HashMap<>();
  37. resultMap.put("url", url);
  38. resultMap.put("code", code);
  39. resultMap.put("msg", msg);
  40. return JSON.toJSONString(resultMap);
  41. }
  42. }

我们用RestController处理了Ajax的跳转请求, 并返回了JSON信息, 让前端进行url跳转

  • 测试的授权Controller

这里的Controller用于显示对应的资源目录下的一些内容, 其中我们从会话中获取了当前登录的用户名

  1. package com.wang.spring_security_framework.controller;
  2. import org.springframework.security.core.Authentication;
  3. import org.springframework.security.core.context.SecurityContextHolder;
  4. import org.springframework.security.core.userdetails.UserDetails;
  5. import org.springframework.web.bind.annotation.RequestMapping;
  6. import org.springframework.web.bind.annotation.RestController;
  7. @RestController
  8. @RequestMapping("/r")
  9. public class AuthorizeTestController {
  10. //从会话中获取当前登录用户名
  11. private String getUserName(){
  12. Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
  13. //未登录, 返回null
  14. if(!authentication.isAuthenticated()) {
  15. return null;
  16. }
  17. Object principal = authentication.getPrincipal();
  18. String username;
  19. if (principal instanceof UserDetails) {
  20. username = ((UserDetails) principal).getUsername();
  21. } else {
  22. username = principal.toString();
  23. }
  24. return username;
  25. }
  26. @RequestMapping("/r1")
  27. public String R1() {
  28. return getUserName() + "访问资源1";
  29. }
  30. @RequestMapping("/r2")
  31. public String R2() {
  32. return getUserName() + "访问资源2";
  33. }
  34. @RequestMapping("/r3")
  35. public String R3() {
  36. return getUserName() + "访问资源3";
  37. }
  38. }

3. 结语

本篇看起来很简单, 事实上也确实很简单......

主要需要理解的是数据库的建立以及关联表的处理, 其中的SQL语句才是最难搞的

访问没有授权的页面, 会爆出 405 错误, 我们可以自定义错误页面来处理这种错误(此处就不叙述了, 属于SpringBoot的内容~)

欢迎小伙伴批评与交流~

SpringSecurity之授权的更多相关文章

  1. 使用SpringSecurity搭建授权认证服务(1) -- 基本demo认证原理

    使用SpringSecurity搭建授权认证服务(1) -- 基本demo 登录认证是做后台开发的最基本的能力,初学就知道一个interceptor或者filter拦截所有请求,然后判断参数是否合理, ...

  2. SpringBoot--- 使用SpringSecurity进行授权认证

    SpringBoot--- 使用SpringSecurity进行授权认证 前言 在未接触 SpringSecurity .Shiro 等安全认证框架之前,如果有页面权限需求需要满足,通常可以用拦截器, ...

  3. [原创]SpringSecurity控制授权(鉴权)功能介绍

    1.spring security 过滤器链 ​ spring security中的除了用户登录校验相关的过滤器,最后还包含了鉴权功能的过滤器,还有匿名资源访问的过滤器链,相关的图解如下: 2.控制授 ...

  4. springsecurity4+springboot 实现remember-me 发现springsecurity 的BUG

    前言:现在开发中,记住我这个功能是普遍的,用户不可能每次登录都要输入用户名密码.昨天准备用spring security的记住我功能,各种坑啊,吐血 . 先看下具体实现吧. spring securi ...

  5. SpringBoot19 集成SpringSecurity01 -> 环境搭建、SpringSecurity验证

    1 环境搭建 1.1 创建一个SpringBoot项目 项目脚手架 -> 点击前往 1.2 创建一个Restful接口 新建一个Controller类即可 package com.example ...

  6. spring-security实现的token授权

    在我的用户密码授权文章里介绍了spring-security的工作过程,不了解的同学,可以先看看用户密码授权这篇文章,在 用户密码授权模式里,主要是通过一个登陆页进行授权,然后把授权对象写到sessi ...

  7. 基于SpringSecurity和JWT的用户访问认证和授权

    发布时间:2018-12-03   技术:springsecurity+jwt+java+jpa+mysql+mysql workBench   概述 基于SpringSecurity和JWT的用户访 ...

  8. 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 环境搭建 创建一 ...

  9. SpringBoot+SpringSecurity之多模块用户认证授权同步

    在之前的文章里介绍了SpringBoot和SpringSecurity如何继承.之后我们需要考虑另外一个问题:当前微服务化也已经是大型网站的趋势,当我们的项目采用微服务化架构时,往往会出现如下情况: ...

随机推荐

  1. maven中pom.xml文件配置

    <properties>                <spring.version>4.3.18.RELEASE</spring.version>        ...

  2. 想买保时捷的运维李先生学Java性能之 运行时数据区域

    前言 不知道自己不知道,不知道自己知道,知道自己不知道,知道自己知道,目前处于知道自己不知道这个阶段,很痛苦啊,干了4年了运维,是一个坎.越来越发觉想要走得远,还是得扎根底.   一.运行时数据区域 ...

  3. 基于SSM框架的JavaWeb通用权限管理系统

    - - ->关注博主公众号[C you again],获取更多IT资源(IT技术文章,毕业设计.课程设计系统源码,经典游戏源码,HTML网页模板,PPT.简历模板,!!还可以投稿赚钱!!,点击查 ...

  4. linux配置java

    https://www.cnblogs.com/zeze/p/5902124.html

  5. Abductive Commonsense Reasoning —— 溯因推理

    Abductive Commonsense Reasoning(溯因推理) 介绍 溯因推理是对不完全观察情境的最合理解释或假设的推论. 上图给出的是一个简明扼要的例子: 给定不同时间节点上的情境观测值 ...

  6. vue-router入门随笔

    下面整理根据官方文档以及自我理解整理,如有不足,请指教. 下面是来自一段官方的原话. Vue Router 是 Vue.js 官方的路由管理器.它和 Vue.js 的核心深度集成,让构建单页面应用变得 ...

  7. javascript常见面试题之一:数组的冒泡排序;

    var arr=[32,2,7,78,90,10]; //外层循环控制轮数: for (var i = 0; i < arr.length; i++) { //内层循环控制次数: for (va ...

  8. java数据结构-04单循环链表

    单循环链表与单链表的不同是,单循环链表尾结点的next指向第一个结点(或头结点)  代码: 无头结点: public class SingleCircleLinkedList<E> ext ...

  9. 基于Vue.js PC桌面端弹出框组件|vue自定义弹层组件|vue模态框

    vue.js构建的轻量级PC网页端交互式弹层组件VLayer. 前段时间有分享过一个vue移动端弹窗组件,今天给大家分享一个最近开发的vue pc端弹出层组件. VLayer 一款集Alert.Dia ...

  10. testNG优雅的使用注解让你的测试项目开发更高效!

    testNG大部分是通过xml配置测试类和监听类 但是这种方法就像传统的spring框架一样需要引入大量的xml配置信息,而且在各层之间也需要通过new对象传递.如果testNG能使用注解注入bean ...