基于 springSecurity 的用户管理脚手架(UMS)

2023-11-07 19:59

本文主要是介绍基于 springSecurity 的用户管理脚手架(UMS),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

UMS (user manage scaffolding) 用户管理脚手架: github gitee

在这里插入图片描述

用户管理脚手架集成:用户密码登录、手机登录、支持所有 JustAuth 支持的第三方授权登录、验证码、基于 RBAC 的 uri 访问权限控制功能、签到等功能。
通过配置文件与实现 用户服务 与 短信发生服务 两个 API 接口就可以实现上述功能,实现快速开发,只需要专注于业务逻辑。

ums-arch


一、UMS 功能列表

  • 验证码(图片,短信, 滑块)校验功能。
  • 手机登录功能,登录后自动注册。
  • 支持所有 JustAuth 支持的第三方授权登录,登录后自动注册或绑定。
    • 支持定时刷新 accessToken, 支持分布式定时任务。
    • 支持第三方授权登录的用户信息表与 token 信息表的缓存功能。
    • 支持第三方绑定与解绑及查询接口(top.dcenter.ums.security.core.oauth.repository.UsersConnectionRepository).
  • 访问权限控制功能。
  • 简化 session、remember me、csrf 等配置。
  • 根据设置的响应方式(JSON 与 REDIRECT)返回 json 或 html 数据。
  • 签到功能。

模块功能

模块功能
core验证码/用户名密码登录/手机登录且自动注册/OAuth2 login by JustAuth/访问权限控制/签到/简化HttpSecurity(session、remember me、csrf 等)配置/session redis 缓存/可配置的响应方式(JSON 与 REDIRECT)返回 json 或 html 数据
demobasic-example/basic-detail-example/permission-example/quickStart/session-detail-example/social-simple-example/social-detail-example/validate-codi-example

demo 演示功能

demo演示功能
basic-examplecore 模块基本功能: 最简单的配置
basic-detail-examplecore 模块基本功能详细的配置: 含anonymous/session简单配置/rememberMe/csrf/登录路由/签到, 不包含session详细配置/验证码/手机登录/权限.
permission-examplecore 模块: 基于 RBAC 的权限功能设置
quickStart快速开始示例
justAuth-security-oauth2-exampleOAuth2 详细示例: 引用的依赖是分离于 core 模块的独立 OAuth2 模块 top.dcenter:justAuth-spring-security-starter:1.0.0, OAuth2 功能都一样.
session-detail-examplecore 模块: session 与 session 缓存详细配置
validate-code-examplecore 模块基本功能: 验证码(含自定义滑块验证码), 手机登录配置
quickStart-1.2.0social 版本快速开始示例
过时:social-simple-examplesocial 模块基本功能: 简单的配置(第三方登录自动注册默认打开)
过时:social-detail-examplesocial 模块功能详细配置: 第三方授权登录注册功能, 统一回调地址路由配置, 第三方登录绑定配置, 第三方授权登录用户信息表自定义与 redis 缓存设置

更新日志


二、maven

<dependency><groupId>top.dcenter</groupId><artifactId>ums-core-spring-boot-starter</artifactId><version>2.0.2</version>
</dependency>

三、TODO List:

    1. 准备基于 spring-security5.4 添加 JWT, OAuth2 authenticate server

四、快速开始

1. 添加依赖:

<dependency><groupId>top.dcenter</groupId><artifactId>ums-core-spring-boot-starter</artifactId><version>2.0.2</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId><version>2.3.4.RELEASE</version>
</dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId><version>2.3.4.RELEASE</version>
</dependency>
<!-- 为了解决 ClassNotFoundException: org.apache.commons.pool2.impl.GenericObjectPoolConfig -->
<dependency><groupId>org.apache.commons</groupId><artifactId>commons-pool2</artifactId><version>2.8.1</version>
</dependency>

2. config:

server:port: 9090spring:profiles:active: dev# mysqldatasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://127.0.0.1:3306/ums?useSSL=false&useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull&serverTimezone=Asia/Shanghaiusername: rootpassword: 123456# session 简单配置session:# session 存储模式设置, 要导入相应的 spring-session 类的依赖, 默认为 none, 分布式应用把 session 放入 redis 等中间件store-type: none# session 过期时间timeout: PT300s# thymeleafthymeleaf:encoding: utf-8prefix: classpath:/templates/suffix: .htmservlet:content-type: text/html;charset=UTF-8# ums core
ums:# ================ 第三方授权登录相关配置 ================oauth:# 是否支持第三方授权登录功能, 默认: trueenabled: true# 第三方服务商: providerIdgithub:# 根据是否有设置 clientId 来动态加载相应 JustAuth 的 AuthXxxRequestclient-id: 4d4ee00e82f669f2ea8dclient-secret: 953ddbe871a08d6924053531e89ecc01d87195a8gitee:client-id: dcc38c801ee88f43cfc1d5c52ec579751c12610c37b87428331bd6694056648eclient-secret: e60a110a2f6e7c930c2d416f802bec6061e19bfa0ceb0df9f6b182b05d8f5a58# 第三方登录授权登录 url 前缀, 不包含 ServletContextPath,默认为 /auth2/authorization.auth-login-url-prefix: /auth2/authorization# 第三方登录回调处理 url 前缀 ,也就是 RedirectUrl 的前缀, 不包含 ServletContextPath,默认为 /auth2/login.redirect-url-prefix: /auth2/login# 第三方登录回调的域名, 例如:http://localhost 默认为 "http://127.0.0.1",# redirectUrl 直接由 {domain}/{servletContextPath}/{redirectUrlPrefix}/{providerId}(ums.oauth.[qq/gitee/weibo])组成domain: http://localhost:9090proxy:# 用于国内代理(HttpClient)超时, 默认 PT3Stimeout: PT3S# 用于国外网站代理(HttpClient)超时, 默认 PT15Sforeign-timeout: PT150S# ================ 密码登录, session, remember-me, csrf等配置 ================client:# 设置登录后返回格式(REDIRECT 与 JSON): 默认 JSONlogin-process-type: redirect# 登录页(必须自己实现)login-page: /login# 登录失败页(必须自己实现)failure-url: /login# 登录成功页(必须自己实现)success-url: /# 设置登出 url, 默认为 /logoutlogout-url: /logout# 设置登出后跳转的 url(必须自己实现), 默认为 /loginlogout-success-url: /login# 不需要认证的静态资源 urls, 例如: /resources/**, /static/**ignoring-urls:- /static/**# 不需要认证的 uri(可以带 HttpMethod 后缀; 用:隔开), 例如: /user/** 或 /user/**:post, 默认为 空 Set.permit-urls:- /hello:GET- /login# 设置登录时用户名的 request 参数名称, 默认为 usernameusernameParameter: username# 设置登录时用户密码的 request 参数名称, 默认为 passwordpasswordParameter: password# ================ 验证码配置 ================# 同一个 uri 由多种验证码同时配置, **优先级**如下:#  `SMS > CUSTOMIZE > SELECTION > TRACK > SLIDER > IMAGE`codes:# 图片验证码image:# 设置需要图片验证码认证的 uri(必须是非 GET 请求),多个 uri 用 “-” 或 ","号分开支持通配符,如:/hello,/user/*;默认为 /authentication/formauth-urls:- /authentication/formrequest-param-image-code-name: imageCode# 短信验证码sms:# 设置需要短信验证码认证的 uri(必须是非 GET 请求),多个 uri 用 “,”号分开支持通配符,如:/hello,/user/*;默认为 /authentication/formauth-urls:- /authentication/mobilerequest-param-mobile-name: mobilerequest-param-sms-code-name: smsCode# ================ 手机登录配置 ================mobile:login:# 手机验证码登录是否开启, 默认 false,# 手机验证码登录开启后 必须配置 ums.codes.sms.auth-urls=/authentication/mobilesms-code-login-is-open: true# 手机验证码登录请求处理url, 默认 /authentication/mobilelogin-processing-url-mobile: /authentication/mobile# ================ 签到配置 ================sign:# redis key(String) 转 byte[] 转换时所用的 charset, 默认: StandardCharsets.UTF_8charset: UTF_8# 用于 redis 签到 key 前缀,默认为: u:sign:sign-key-prefix: 'u:sign:'# 用于 redis 总签到 key 前缀,默认为: total:sign:total-sign-key-prefix: 'total:sign:'# 获取最近几天的签到情况, 不能大于 28 天, 默认为 7 天last-few-days: 7# 用户签到 redis key TTL, 默认: 二个月 , 单位: 秒total-expired: 5356800# 用户签到统计 redis key TTL, 默认: 二个月 , 单位: 秒user-expired: 2678400---
spring:profiles: devmvc:throw-exception-if-no-handler-found: truethymeleaf:cache: false#debug: trueserver:port: 9090servlet:context-path: /demo

3. 实现 UmsUserDetailsService 接口等:

UserDetailsService.java
package top.dcenter.ums.security.core.demo.service;import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthUser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserCache;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.ServletWebRequest;
import top.dcenter.ums.security.common.enums.ErrorCodeEnum;
import top.dcenter.ums.security.core.api.service.UmsUserDetailsService;
import top.dcenter.ums.security.core.exception.RegisterUserFailureException;
import top.dcenter.ums.security.core.exception.UserNotExistException;import java.util.List;/***  用户密码与手机短信登录与注册服务:<br><br>*  1. 用于第三方登录与手机短信登录逻辑。<br><br>*  2. 用于用户密码登录逻辑。<br><br>*  3. 用户注册逻辑。<br><br>* @author YongWu zheng* @version V1.0  Created by 2020/9/20 11:06*/
@Service
@Slf4j
public class UserDetailsServiceImpl implements UmsUserDetailsService {/*** 用户名*/public static final String PARAM_USERNAME = "username";/*** 密码*/public static final String PARAM_PASSWORD = "password";private final ObjectMapper objectMapper;private final JdbcTemplate jdbcTemplate;@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")@Autowired(required = false)private UserCache userCache;/*** 用于密码加解密*/@SuppressWarnings("SpringJavaAutowiredFieldsWarningInspection")@Autowiredprivate PasswordEncoder passwordEncoder;public UserDetailsServiceImpl(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;this.objectMapper = new ObjectMapper();objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}@SuppressWarnings("AlibabaUndefineMagicConstant")@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {try{// 从缓存中查询用户信息:// 从缓存中查询用户信息if (this.userCache != null){UserDetails userDetails = this.userCache.getUserFromCache(username);if (userDetails != null){return userDetails;}}// 根据用户名获取用户信息// 获取用户信息逻辑。。。// ...// 示例:只是从用户登录日志表中提取的信息,log.info("Demo ======>: 登录用户名:{}, 登录成功", username);return new User(username,passwordEncoder.encode("admin"),true,true,true,true,AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_VISIT, ROLE_USER"));}catch (Exception e){String msg = String.format("Demo ======>: 登录用户名:%s, 登录失败: %s", username, e.getMessage());log.error(msg, e);throw new UserNotExistException(ErrorCodeEnum.QUERY_USER_INFO_ERROR, e, username);}}@Overridepublic UserDetails registerUser(String mobile) throws RegisterUserFailureException {if (mobile == null){throw new RegisterUserFailureException(ErrorCodeEnum.MOBILE_NOT_EMPTY, null);}// 用户信息持久化逻辑。。。// ...log.info("Demo ======>: 手机短信登录用户 {}:注册成功", mobile);User user = new User(mobile,passwordEncoder.encode("admin"),true,true,true,true,AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_VISIT, ROLE_USER"));// 把用户信息存入缓存if (userCache != null){userCache.putUserInCache(user);}return user;}@Overridepublic UserDetails registerUser(ServletWebRequest request) throws RegisterUserFailureException {String username = getValueOfRequest(request, PARAM_USERNAME, ErrorCodeEnum.USERNAME_NOT_EMPTY);String password = getValueOfRequest(request, PARAM_PASSWORD, ErrorCodeEnum.PASSWORD_NOT_EMPTY);// ...// UserInfo userInfo = getUserInfo(request)// 用户信息持久化逻辑。。。// ...String encodedPassword = passwordEncoder.encode(password);log.info("Demo ======>: 用户名:{}, 注册成功", username);User user = new User(username,encodedPassword,true,true,true,true,AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_VISIT, ROLE_USER"));// 把用户信息存入缓存if (userCache != null){userCache.putUserInCache(user);}return user;}@Overridepublic UserDetails registerUser(AuthUser authUser, String username, String defaultAuthority) throws RegisterUserFailureException {// 第三方授权登录不需要密码, 这里随便设置的, 生成环境按自己的逻辑String encodedPassword = passwordEncoder.encode(authUser.getUuid());List<GrantedAuthority> grantedAuthorities = AuthorityUtils.commaSeparatedStringToAuthorityList(defaultAuthority);// ... 用户注册逻辑log.info("Demo ======>: 用户名:{}, 注册成功", username);// @formatter:offUserDetails user = User.builder().username(username).password(encodedPassword).disabled(false).accountExpired(false).accountLocked(false).credentialsExpired(false).authorities(grantedAuthorities).build();// @formatter:off// 把用户信息存入缓存if (userCache != null){userCache.putUserInCache(user);}return user;}@Overridepublic UserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {UserDetails userDetails = loadUserByUsername(userId);User.withUserDetails(userDetails);return User.withUserDetails(userDetails).build();}@Overridepublic List<Boolean> existedByUserIds(String... userIds) throws UsernameNotFoundException {// ... 在本地账户上查询 userIds 是否已被使用return List.of(true, false, false);}private String getValueOfRequest(ServletWebRequest request, String paramName, ErrorCodeEnum usernameNotEmpty) throws RegisterUserFailureException {String result = request.getParameter(paramName);if (result == null){throw new RegisterUserFailureException(usernameNotEmpty, request.getSessionId());}return result;}
}
UserController.java
package top.dcenter.ums.security.core.demo.controller;import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import top.dcenter.ums.security.core.permission.config.EnableUriAuthorize;import java.util.HashMap;
import java.util.Map;/**** @author YongWu zheng* @version V1.0  Created by 2020/9/20 20:04*/
@Controller
@Slf4j
@EnableUriAuthorize()
public class UserController {@GetMapping("/login")public String login() {return "login";}@GetMapping("/")public String index(@AuthenticationPrincipal UserDetails userDetails, Model model) {if (userDetails != null){model.addAttribute("username", userDetails.getUsername());model.addAttribute("roles", userDetails.getAuthorities());}else{model.addAttribute("username", "anonymous");model.addAttribute("roles", "ROLE_VISIT");}return "index";}@GetMapping("/me")@ResponseBodypublic Object getCurrentUser(@AuthenticationPrincipal UserDetails userDetails, Authentication authentication) {Map<String, Object> map = new HashMap<>(16);map.put("authenticationHolder", SecurityContextHolder.getContext().getAuthentication());map.put("userDetails", userDetails);map.put("authentication", authentication);return map;}}

4. 前端页面 :

login.htm: 放在 classpath:/templates/
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>登录</title><script type="text/javascript" src="https://cdn.jsdelivr.net/npm/jquery@1.11.1/dist/jquery.min.js"></script></head>
<body>
<h2>登录页面</h2>
<h3>表单登录</h3>
<h5>如果短信验证码与图片验证码同时配置时,优先使用短信验证码,图片验证码失效</h5>
<!-- 通过 th:action 的方式支持 csrf 或者 添加隐藏域<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> -->
<form id="reg-form" th:action="@{/authentication/form}" method="post"><table><tr><td>用户名:</td><td><input type="text" name="username" value="admin" ><p style="color: #ff0000"id="error-name"></p></td></tr><tr><td>密码:</td><td><input type="password" name="password" value="admin"></td></tr><tr><td>图形验证码:</td><td><input type="text" name="imageCode"><img class="img" th:src="@{/code/image}" style="width: 67px; height: 23px"></td></tr><tr><td ><input type="checkbox" name="rememberMe" checked="true">记住我</input></td><td><p style="color: #ff0000" id="error-code"></p></td></tr><tr><td ><button id="btn-reg" type="button">登录ajax</button></td><!-- 通过 form submit 不能接收错误信息, 通过 ajax 可接收错误信息 --><td ><button type="submit">登录</button></td></tr></table>
</form>
<h3>手机登录</h3>
<form id="mobile-form" th:action="@{/authentication/mobile}" method="post"><table><tr><td>手机号码:</td><td><input type="tel" name="mobile" value="13345678980"><p style="color: #ff0000"id="error-name-mobile"></p><a th:href="@{/code/sms?mobile=13345678980}" >发送验证码</a></td></tr><tr><td>手机验证码:</td><td><input type="text" name="smsCode"></td></tr><tr><td ><input type="checkbox" name="rememberMe" checked="true">记住我</input></td><td><p style="color: #ff0000" id="error-code-mobile"></p></td></tr><tr><td ><button id="btn-mobile" type="button">登录ajax</button></td><!-- 通过 form submit 不能接收错误信息, 通过 ajax 可接收错误信息 --><td ><button type="submit">登录</button></td></tr></table>
</form>
<br><br>
<h3>社交登录</h3>
<a th:href="@{/auth2/authorization/gitee}">gitee登录</a>
<a th:href="@{/auth2/authorization/github}">github登录</a>
<a th:href="@{/auth2/authorization/gitee}">github登录</a><dev id="basePath" th:basePath="@{/}" style="display: none"/>
</body>
<script>var basePath = $("#basePath").attr("basePath");$.fn.serializeObject = function(){let o = {};let 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;}$(".img").click(function(){let uri = this.getAttribute("src");console.log(uri)let end = uri.indexOf('?', 0);console.log(end)if (end === -1) {uri = uri + '?'+ Math.random();} else {uri = uri.substring(0, end) + '?'+ Math.random();}console.log(uri)this.setAttribute('src', uri);});function submitFormByAjax(url, formId, errorNameId, errorCodeId, imgId, refresh) {return function () {console.log(JSON.stringify($(formId).serializeObject()))$.ajax({// 如果用的是模板,则 url 可以使用注入的方式,会跟着配置动态改变url: url,data: JSON.stringify($(formId).serializeObject()),type: "POST",dataType: "json",success: function (data) {$(errorNameId).text("")$(errorCodeId).text("")console.log("==========注册成功============")// 注册成功// ...console.log(data)let uri = data.data.targetUrlif (uri === null) {uri = basePath}window.location.href = uri;},error: function (data) {// 注册失败$(errorNameId).text("")$(errorCodeId).text("")console.log("********注册失败*********")console.log(data)data = data.responseJSONif (undefined !== data) {console.log(data);// 错误代码看ErrorCodeEnumif (data.code >= 900 && data.code < 1000) {$(errorNameId).text(data.msg)} else if (data.code >= 600 && data.code < 700) {$(errorCodeId).text(data.msg)}}if (refresh) {$(imgId).trigger("click");}}})return};}$("#btn-mobile").click(submitFormByAjax($("#mobile-form").attr("action"), "#mobile-form", "#error-name-mobile", "#error-code-mobile", ".img-mobile", true))$("#btn-reg").click(submitFormByAjax($("#reg-form").attr("action"), "#reg-form", "#error-name", "#error-code", ".img", true))</script>
</html>
index.htm
<!DOCTYPE html>
<html xmlns:th="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>index</title>
</head>
<body>
hello <span th:text="${username}">world!</span><br>
roles: <span th:text="${roles}"/><!-- 通过 th:action 的方式支持 csrf 或者 添加隐藏域<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}"/> --><form th:action="@{/logout?logout}" method="post"><input type="submit" value="退出登录post"/></form>
</body>
</html>

5. 访问前端页面

  • 浏览器访问 http://localhost:9090/demo/login, 至此集成了:登录校验,验证码、手机登录、第三方登录(JustAuth)、基于 RBAC 的 uri 访问权限控制功能, 签到等功能; 实现快速开发。
  • Quick Start 代码在 demo 模块 -> quickStart, 其他功能的详细配置说明参照: Configurations。

五、接口使用说明:

实现对应功能时需要实现的接口:

  1. 用户服务: 必须实现
    • UmsUserDetailsService
  2. 图片验证码: 如果不实现就会使用默认图片验证码, 实时产生验证码图片, 没有缓存功能
    • ImageCodeFactory
  3. 短信验证码: 默认空实现
    • SmsCodeSender
  4. 滑块验证码: 如果不实现就会使用默认滑块验证码, 实时产生验证码图片, 没有缓存功能
    • SimpleSliderCodeFactory
  5. 自定义验证码:
    • AbstractValidateCodeProcessor
    • ValidateCodeGenerator
  6. 访问权限控制功能: 基于 RBAC 的访问权限控制, 增加了更加细粒度的权限控制, 支持 restfulApi; 如: 对菜单与按钮的权限控制
    • AbstractUriAuthorizeService:
      • AbstractUriAuthorizeService 类中的方法getRolesAuthorities();
        getRolesAuthorities()返回值: Map<role, Map<uri, UriResourcesDTO>> 中UriResourcesDTO字段 uri
        permission 必须有值.
      • 默认实现了 hasPermission(..) 表达式, 实现 AbstractUriAuthorizeService 即生效,
        1. 默认启用 httpSecurity.authorizeRequests().anyRequest().access(“hasPermission(request, authentication)”); 方式.
        2. 如果开启注解方式( @UriAuthorize 或 @EnableGlobalMethodSecurity(prePostEnabled = true) ): 则通过注解 @PerAuthority
          (“hasPermission(’/users/’, '/users/:list’)”) 方式生效.

六、Configurations:

功能模块demo模块–简单配置demo模块–详细配置
1. 基本功能corebasic-example
2. 登录路由功能corebasic-detail-example
3. sessioncoresession-detail-example
4. remember-mecorebasic-detail-example
5. csrfcorebasic-detail-example
6. anonymouscorebasic-detail-example
7. 验证码corevalidate-code-example
8. 手机登录corebasic-detail-example
9. 第三方登录corebasic-detail-example
10. 给第三方登录时用的数据库表 user_connection 与 auth_token 添加 redis cachecorebasic-detail-example
11. 签到corebasic-detail-example
12. 基于 RBAC 的访问权限控制功能corepermission-example
13. 线程池配置corejustAuth-security-oauth2-example

七、注意事项:

1. 基于 RBAC 的 uri 访问权限控制

  • 更新角色权限时必须调用 AbstractUriAuthorizeService#updateRolesAuthorities() 方法来刷新权限, 即可实时刷新角色权限.
    • 刷新权限有两种方式:一种发布事件,另一种是直接调用服务;推荐用发布事件(异步执行)。
      1. 推荐用发布事件(异步执行)
        applicationContext.publishEvent(new UpdateRolesAuthoritiesEvent(true));
      2. 直接调用服务
        abstractUriAuthorizeService.updateRolesAuthorities();

2. HttpSecurity 配置问题:UMS 中的 HttpSecurityAware 配置与应用中的 HttpSecurity 配置冲突问题:

  1. 如果是新建应用添加 HttpSecurity 配置, 通过下面的接口即可:
    • HttpSecurityAware
  2. 如果是已存在的应用:
    • 添加 HttpSecurity 配置, 通过下面的接口即可: HttpSecurityAware
    • 已有的 HttpSecurity 配置, 让原有的 HttpSecurity 配置实现此接口进行配置: top.dcenter.security.core.api.config.HttpSecurityAware

3. 在 ServletContext 中存储的属性:

  • 属性名称: SecurityConstants.SERVLET_CONTEXT_AUTHORIZE_REQUESTS_MAP_KEY
  • 属性值: authorizeRequestMap<String, Set>: key 为 PERMIT_ALL, DENY_ALL, ANONYMOUS, AUTHENTICATED
    , FULLY_AUTHENTICATED, REMEMBER_ME 的权限类型, value 为 UriHttpMethodTuple(uri不包含 servletContextPath)的 set.

4. servletContextPath 的值存储在 MvcUtil.servletContextPath :

  • 通过静态方法获取 MvcUtil.getServletContextPath()
  • MvcUtil.servletContextPath 的值是通过: SecurityAutoConfiguration#afterPropertiesSet() 接口注入

5. 验证码优先级:

  • 同一个 uri 由多种验证码同时配置, 优先级如下:
    SMS > CUSTOMIZE > SELECTION > TRACK > SLIDER > IMAGE

八、属性配置列表

属性配置列表
基本属性
签到属性
手机登录属性
验证码属性
第三方授权登录
线程池属性
第三方授权登录用户信息数据 redis 缓存配置
第三方授权登录用户信息表 user_connection sql 配置
过时:social_userConnection redisCache属性
过时:social属性

九、参与贡献

  1. Fork 本项目
  2. 新建 Feat_xxx 分支
  3. 提交代码
  4. 新建 Pull Request

十、流程图: 随着版本迭代会有出入

1. 滑块验证码

sliderValidateCode

七、时序图(Sequence Diagram)

crsf

crsf

getValidateCode

getValidateCode

ImageValidateCodeLogin

ImageValidateCodeLogin

logout

logout

rememberMe

rememberMe

scurityConfigurer

scurityConfigurer

securityRouter

securityRouter

session

session

SmsCodeLogin

SmsCodeLogin

这篇关于基于 springSecurity 的用户管理脚手架(UMS)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/365961

相关文章

JVM 的类初始化机制

前言 当你在 Java 程序中new对象时,有没有考虑过 JVM 是如何把静态的字节码(byte code)转化为运行时对象的呢,这个问题看似简单,但清楚的同学相信也不会太多,这篇文章首先介绍 JVM 类初始化的机制,然后给出几个易出错的实例来分析,帮助大家更好理解这个知识点。 JVM 将字节码转化为运行时对象分为三个阶段,分别是:loading 、Linking、initialization

Spring Security 基于表达式的权限控制

前言 spring security 3.0已经可以使用spring el表达式来控制授权,允许在表达式中使用复杂的布尔逻辑来控制访问的权限。 常见的表达式 Spring Security可用表达式对象的基类是SecurityExpressionRoot。 表达式描述hasRole([role])用户拥有制定的角色时返回true (Spring security默认会带有ROLE_前缀),去

浅析Spring Security认证过程

类图 为了方便理解Spring Security认证流程,特意画了如下的类图,包含相关的核心认证类 概述 核心验证器 AuthenticationManager 该对象提供了认证方法的入口,接收一个Authentiaton对象作为参数; public interface AuthenticationManager {Authentication authenticate(Authenti

Spring Security--Architecture Overview

1 核心组件 这一节主要介绍一些在Spring Security中常见且核心的Java类,它们之间的依赖,构建起了整个框架。想要理解整个架构,最起码得对这些类眼熟。 1.1 SecurityContextHolder SecurityContextHolder用于存储安全上下文(security context)的信息。当前操作的用户是谁,该用户是否已经被认证,他拥有哪些角色权限…这些都被保

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

Java架构师知识体认识

源码分析 常用设计模式 Proxy代理模式Factory工厂模式Singleton单例模式Delegate委派模式Strategy策略模式Prototype原型模式Template模板模式 Spring5 beans 接口实例化代理Bean操作 Context Ioc容器设计原理及高级特性Aop设计原理Factorybean与Beanfactory Transaction 声明式事物

Java进阶13讲__第12讲_1/2

多线程、线程池 1.  线程概念 1.1  什么是线程 1.2  线程的好处 2.   创建线程的三种方式 注意事项 2.1  继承Thread类 2.1.1 认识  2.1.2  编码实现  package cn.hdc.oop10.Thread;import org.slf4j.Logger;import org.slf4j.LoggerFactory

综合安防管理平台LntonAIServer视频监控汇聚抖动检测算法优势

LntonAIServer视频质量诊断功能中的抖动检测是一个专门针对视频稳定性进行分析的功能。抖动通常是指视频帧之间的不必要运动,这种运动可能是由于摄像机的移动、传输中的错误或编解码问题导致的。抖动检测对于确保视频内容的平滑性和观看体验至关重要。 优势 1. 提高图像质量 - 清晰度提升:减少抖动,提高图像的清晰度和细节表现力,使得监控画面更加真实可信。 - 细节增强:在低光条件下,抖

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听