spring security +MySQL + BCryptPasswordEncoder 单向加密验证 + 权限拦截 --- 心得
1.前言
前面学习了 security的登录与登出 , 但是用户信息 是 application 配置 或内存直接注入进去的 ,不具有实用性,实际上的使用还需要权限管理,有些 访问接口需要某些权限才可以使用
于是多了个权限管理的问题
2.环境
spring boot 2.1.6.RELEASE
mysql 5.5.28*win64
jdk 1.8.0_221
3.操作
(1)准备一张MySQL表
CREATE TABLE `t_user` (
`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键,自递增',
`username` varchar(20) DEFAULT NULL COMMENT '用户名',
`psw` varchar(140) DEFAULT NULL COMMENT '密码',
`nickname` varchar(50) DEFAULT NULL COMMENT '别名',
`role` varchar(100) DEFAULT NULL COMMENT '权限名',
`setTime` datetime DEFAULT NULL COMMENT '注册时间',
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;
(2)目录结构
(3)pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>security-5500</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>security-5500</name>
<description>Demo project for Spring Boot</description> <properties>
<!-- 设置项目编码格式-->
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties> <dependencies>
<!--spring security 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency> <!--访问静态资源-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- MySQL 依赖-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!-- <scope>runtime</scope>-->
<version>5.1.30</version>
</dependency>
<!--MySQL 数据源 依赖包-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.1.10</version>
</dependency> <!-- mybatis依赖-->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.2</version>
</dependency>
<!-- mybatis的逆向工程依赖包-->
<dependency>
<groupId>org.mybatis.generator</groupId>
<artifactId>mybatis-generator-core</artifactId>
<version>1.3.2</version>
</dependency>
<!-- SCryptPasswordEncoder 加密才需要使用-->
<dependency>
<groupId>org.bouncycastle</groupId>
<artifactId>bcprov-jdk15on</artifactId>
<version>1.64</version>
</dependency>
<!--java工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>
(4)配置mybatis 与 dao层接口【具体操作这里不演示,可看我的其他随笔有具体讲解】
(5)配置前端页面
index.html
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>index</title>
</head>
<body>
你好 ,世界 ,2333
<p>点击 <a th:href="@{/home}">我</a> 去home.html页面</p> </body>
</html>
home.html
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>security首页</title>
</head>
<body>
<h1>Welcome!你好,世界</h1> <p>Click <a th:href="@{/hai}">here</a> to see a greeting.</p>
</body>
</html>
hai.html
<!DOCTYPE html>
<html lang="zh" xmlns="http://www.w3.org/1999/xhtml"
xmlns:th="http://www.thymeleaf.org" xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<meta charset="UTF-8">
<title>hai文件</title>
</head>
<body>
你好呀世界,成功登录进来了
<br>
<hr>
用户名:<span th:text="${username}"></span>
<hr>
<!-- 登出 路径是在security 拦截规则 那 设置的 ,当然也可以使用自己写的 ,必须post方式才可以访问,因为默认开启了CSRF -->
<form th:action="@{/mylogout}" method="post">
<button class="btn btn-danger" style="margin-top: 20px">退出登录</button>
</form>
</body>
</html>
kk.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>kk</title>
</head>
<body>
<img src="img/xx.png" alt="">
</body>
</html>
login.html
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
<title>Spring Security自定义</title>
</head>
<body>
<div th:if="${param.error}">
Invalid username and password.
</div>
<div th:if="${param.logout}">
You have been logged out.
</div>
<form th:action="@{/login}" method="post">
<div><label> User Name : <input type="text" name="username"/> </label></div>
<div><label> Password: <input type="password" name="password"/> </label></div>
<div><input type="submit" value="Sign In"/></div>
</form>
<br>
lalallalalal啊是德国海
</body>
</html>
(6)配置controller 虚拟路径 【访问接口】
package com.example.security5500.controller; import org.springframework.security.access.annotation.Secured;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.ModelAndView; import java.security.Principal; @Controller
public class MVCController { @RequestMapping("/home")
public String home() {
return "home";
} @RequestMapping("/login")
public String login(){
return "login";
} @RequestMapping("/hai")
public String hai(@AuthenticationPrincipal Principal principal, Model model) {
//获取登录用户名信息 ,如果没有登录 principal.getName() 会报异常,因此弄个异常抛出
String s= "r";
try {
if (principal.getName() !=null){
s = principal.getName();
}
}catch (Exception e){
System.out.println("principal.getName()出异常");
} model.addAttribute("username", s);
return "hai";
} @RequestMapping({"/", "/index"})
public String index() {
return "index";
} @RequestMapping("kk")
public String kk() {
return "kk";
} //获取用户权限
@RequestMapping({"/info"})
@ResponseBody
public Object info(@AuthenticationPrincipal Principal principal) {
return principal;
}
/*
{"authorities":[{"authority":"admin"},{"authority":"user"}],
"details":{"remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"1F57B8E39C5D1DB1F875D57D533DB982"},
"authenticated":true,"principal":{"password":null,"username":"xi","authorities":[{"authority":"admin"},
{"authority":"user"}],"accountNonExpired":true,"accountNonLocked":true,
"credentialsNonExpired":true,"enabled":true},"credentials":null,"name":"xi"} */ }
package com.example.security5500.controller; import com.example.security5500.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody; import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.security.Principal;
import java.util.Map; @Controller
@RequestMapping("/admin")
public class UserController { @Autowired
private UserService userService; // //登出操作
// @RequestMapping({"/lo"})
// public String logout(HttpServletRequest request, HttpServletResponse response) {
// Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// if (auth != null) {//清除认证
// new SecurityContextLogoutHandler().logout(request, response, auth);
// }
// //重定向到指定页面
// return "redirect:/login";
// } //添加用户
@RequestMapping({"/addUser"})
@ResponseBody
public Map<String,Object> addUser(String username , String psw ) {
return userService.addUser(username,psw);
} }
(7)service层实现类
package com.example.security5500.service.serviceImpl; import com.example.security5500.dao.TUserMapper;
import com.example.security5500.entitis.tables.TUser;
import com.example.security5500.service.UserService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service; import javax.annotation.Resource;
import java.util.Date;
import java.util.HashMap;
import java.util.Map; @Service
public class UserServiceImpl implements UserService { @Resource
private TUserMapper tUserMapper; //根据用户名获取用户信息
@Override
public TUser getByUsername(String useranme) {
return tUserMapper.selectByUsername(useranme);
} //添加新用户
@Override
public Map<String,Object> addUser(String username, String psw) {
Map<String,Object> map = new HashMap<>();
if (StringUtils.isBlank(username) || StringUtils.isBlank(psw))
{
map.put("data","参数不可空");
return map;
} ////根据用户名获取用户信息
TUser u = tUserMapper.selectByUsername(username);
if (u!= null){
map.put("data","用户名已经存在");
return map;
}
//
TUser tUser = new TUser();
tUser.setUsername(username);
//
//BCryptPasswordEncoder 单向加密
tUser.setPsw((new BCryptPasswordEncoder()).encode(psw));
//
tUser.setNickname("别名-昵称");
tUser.setRole("user");
tUser.setSettime(new Date());
int len = tUserMapper.insertSelective(tUser);
if (len!=1){
map.put("data","失败");
}else {
map.put("data","成功");
}
return map;
}
}
(8)启动类
package com.example.security5500; import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.web.servlet.config.annotation.EnableWebMvc; @SpringBootApplication
//设置mapper接口包位置
@MapperScan(basePackages = "com.example.security5500.dao")
public class Security5500Application { public static void main(String[] args) {
SpringApplication.run(Security5500Application.class, args);
} }
(9)security配置类 ,继承了 WebSecurityConfigurerAdapter ,重写了父类方法 ,可对访问路径自定义设置拦截规则
package com.example.security5500.securityConfig; import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Component; //这个加不加无所谓
//@Configuration
//开启security自定义配置
@EnableWebSecurity
//开启 Controller层的访问方法权限,与注解@PreAuthorize("hasRole('admin')")配合,但是 经测试,无法使用,前端访问指定接口报错403 ,
//@EnableGlobalMethodSecurity(prePostEnabled=true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { //实例自定义登录校验接口 【内部有 数据库查询】
@Autowired
private DbUserDetailsService dbUserDetailsService; //拦截规则设置
@Override
protected void configure(HttpSecurity http) throws Exception {
http
//允许基于使用HttpServletRequest限制访问
.authorizeRequests()
//设置不拦截页面,可直接通过,路径访问 "/", "/index", "/home" 则不拦截, .antMatchers("/", "/index", "/home", "/hhk/**")
//是允许所有的意思
.permitAll()
//访问 /hai 需要admin权限 ,无权限则提示 403
.antMatchers("/hai").hasAuthority("admin")
//访问 /kk 需要admin或user权限 ,无权限则提示 403
.antMatchers("/kk").hasAnyAuthority("admin","user")
//路径/admin/**所有的请求都需要admin权限 ,无权限则提示 403
.antMatchers("/admin/**").hasAuthority("admin")
//其他页面都要拦截,【需要在最后设置这个】
.anyRequest().authenticated()
.and()
//设置自定义登录页面
.formLogin()
//指定自定义登录页面的访问虚拟路径
.loginPage("/login")
.permitAll()
.and()
// 添加退出登录支持。当使用WebSecurityConfigurerAdapter时,这将自动应用。默认情况是,访问URL”/ logout”,使HTTP Session无效
// 来清除用户,清除已配置的任何#rememberMe()身份验证,清除SecurityContextHolder,然后重定向到”/login?success”
.logout()
// //指定的登出操作的虚拟路径,需要以post方式请求这个 http://localhost:5500/mylogout 才可以登出 ,也可以直接清除用户认证信息达到登出目的
.logoutUrl("/mylogout")
//登出成功后访问的地址
.logoutSuccessUrl("/home");
} /**
* 添加 UserDetailsService, 实现自定义登录校验,数据库查询
*/
@Override
protected void configure(AuthenticationManagerBuilder builder) throws Exception {
//注入用户信息,每次登录都会来这查询一次信息,因此不建议每次都向mysql查询,应该使用redis
//密码加密
builder.userDetailsService(dbUserDetailsService).passwordEncoder(passwordEncoder());
} /**
* BCryptPasswordEncoder相关知识:
* 用户表的密码通常使用MD5等不可逆算法加密后存储,为防止彩虹表破解更会先使用一个特定的字符串(如域名)加密,然后再使用一个随机的salt(盐值)加密。
* 特定字符串是程序代码中固定的,salt是每个密码单独随机,一般给用户表加一个字段单独存储,比较麻烦。
* BCrypt算法将salt随机并混入最终加密后的密码,验证时也无需单独提供之前的salt,从而无需单独处理salt问题。
*/
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
} // /**
// * 选择加密方式 ,密码不加密的时候选择 NoOpPasswordEncoder,不可缺少,否则报错
// * java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
// */
// @Bean
// public static PasswordEncoder passwordEncoder() {
// return NoOpPasswordEncoder.getInstance();
// } }
(10)实现自定义登录校验,实现了根据用户名去数据库查询用户信息,集齐参数用户名、加密后的密码、权限 ,
然后使用 new org.springframework.security.core.userdetails.User(tUser.getUsername(), tUser.getPsw(), simpleGrantedAuthorities); 注册登录用户 ,
然后内部会自动对比密码 进行校验 【使用 BCryptPasswordEncoder 单项加密】
package com.example.security5500.securityConfig; import com.example.security5500.entitis.tables.TUser;
import com.example.security5500.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service; import java.util.ArrayList;
import java.util.List; @Service
public class DbUserDetailsService implements UserDetailsService { @Autowired
private UserService userService; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名查询用户信息
TUser tUser = userService.getByUsername(username);
if (tUser == null){
throw new UsernameNotFoundException("用户不存在!");
}
//权限设置
// List<GrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
List<SimpleGrantedAuthority> simpleGrantedAuthorities = new ArrayList<>();
String role = tUser.getRole();
//分割权限名称,如 user,admin
String[] roles = role.split(",");
System.out.println("添加权限");
for (String r :roles){
System.out.println(r);
//添加权限
simpleGrantedAuthorities.add(new SimpleGrantedAuthority(r));
} // simpleGrantedAuthorities.add(new SimpleGrantedAuthority("USER"));
/**
* 创建一个用于认证的用户对象并返回,包括:用户名,密码,角色
*/
//输入参数
return new org.springframework.security.core.userdetails.User(tUser.getUsername(), tUser.getPsw(), simpleGrantedAuthorities);
} }
(11)application.properties
spring.application.name=security-5500
# 应用服务web访问端口
server.port=5500
#配置security登录账户密和密码 ,不配置则默认账户是user,密码是随机生成的字符串,打印在启动栏中
#spring.security.user.name=11
#spring.security.user.password=22
#
##
##
##
## Enable template caching.
#spring.thymeleaf.cache=true
## Check that the templates location exists.
#spring.thymeleaf.check-template-location=true
## Content-Type value.
##spring.thymeleaf.content-type=text/html
## Enable MVC Thymeleaf view resolution.
#spring.thymeleaf.enabled=true
## Template encoding.
#spring.thymeleaf.encoding=utf-8
## Comma-separated list of view names that should be excluded from resolution.
#spring.thymeleaf.excluded-view-names=
## Template mode to be applied to templates. See also StandardTemplateModeHandlers.
#spring.thymeleaf.mode=HTML5
## Prefix that gets prepended to view names when building a URL.
##设置html文件位置
#spring.thymeleaf.prefix=classpath:/templates/
## Suffix that gets appended to view names when building a URL.
#spring.thymeleaf.suffix=.html spring.thymeleaf.template-resolver-order=
# Order of the template resolver in the chain. spring.thymeleaf.view-names= # Comma-separated list of view names that can be resolved.
#
#
#设置mybatis
#mybatis设置
#mybatis配置文件所在路径
mybatis.config-location=classpath:mybatis/config/mybatisConfig.xml
#所有Entity别名类所在包
mybatis.type-aliases-package=com.example.security5500.entitis.tables
#mapper映射xml文件[也可以放在 resources 里面]
#不论放在哪里,都必须使用classpath: 否则找不到 ,报错 org.apache.ibatis.binding.BindingException: Invalid bound statement (not found):
mybatis.mapper-locations= classpath:mybatis/mapper/**/*.xml #mysql配置
# 当前数据源操作类型
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
# mysql驱动包
spring.datasource.driver-class-name=org.gjt.mm.mysql.Driver
# 数据库名称
spring.datasource.url=jdbc:mysql://localhost:3306/security?characterEncoding=utf-8
# 数据库账户名
spring.datasource.username=root
# 数据库密码
spring.datasource.password=mysql
#
#
# 数据库连接池的最小维持连接数
spring.datasource.dbcp2.min-idle=5
# 初始化连接数
spring.datasource.dbcp2.initial-size=5
# 最大连接数
spring.datasource.dbcp2.max-total=5
# 等待连接获取的最大超时时间
spring.datasource.dbcp2.max-wait-millis=200
#
# 指明是否在从池中取出连接前进行检验,如果检验失败, 则从池中去除连接并尝试取出另一个,
#注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串
spring.datasource.druid.test-on-borrow=false
#
# 指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败,则连接将被从池中去除.
#注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串
spring.datasource.druid.test-while-idle=true
#
# 指明是否在归还到池中前进行检验,注意: 设置为true后如果要生效,
#validationQuery参数必须设置为非空字符串
spring.datasource.druid.test-on-return=false
#
# SQL查询,用来验证从连接池取出的连接,在将连接返回给调用者之前.
#如果指定,则查询必须是一个SQL SELECT并且必须返回至少一行记录
spring.datasource.druid.validation-query=select 1
4.测试
(1)启动 默认进入 index.html
点击 “我” ,进入 home.html
点击 “here” ,进入 hai.html ,但是因为设置了拦截,需要登录才可以访问 ,因此进入了自定义的登录页面
用一个只有 user权限的账户
username = cen
password = 11
登录后显示 403
因为我将访问 hai.html的权限设为需要 admin 才可以访问 ,因此拒绝操作
换一个有admin权限的账户
username = xi
password = 11
访问网址http://localhost:5500/login
再次登录
这是对一个终端访问接口的权限拦截
那么,需要将某一路径的请求都给拦截怎么办?难道一个一个写?
不,可以拦截上一层的虚拟路径
security的的配置写法
(2)一个拦截路径可以设置多个权限,只要有任意一个权限都可以访问
网址访问 http://localhost:5500/kk ,【无权限仍然提示403】
spring security +MySQL + BCryptPasswordEncoder 单向加密验证 + 权限拦截 --- 心得的更多相关文章
- 基于spring security 实现前后端分离项目权限控制
前后端分离的项目,前端有菜单(menu),后端有API(backendApi),一个menu对应的页面有N个API接口来支持,本文介绍如何基于spring security实现前后端的同步权限控制. ...
- Spring Security教程之基于方法的权限控制(十二)
目录 1.1 intercept-methods定义方法权限控制 1.2 使用pointcut定义方法权限控制 1.3 使用注解定义方法权限控制 1.3.1 JSR-25 ...
- vue路由守卫用于登录验证权限拦截
vue路由守卫用于登录验证权限拦截 vue路由守卫 - 全局(router.beforeEach((to, from, next) =>来判断登录和路由跳转状态) 主要方法: to:进入到哪个路 ...
- spring security的BCryptPasswordEncoder加密和对密码验证的原理
目录 BCryptPasswordEncoder加密和对密码验证的原理 一.加密算法和hash算法的区别 二.源码解析 1. encode方法 2. BCrypt.hashpw方法 3. matche ...
- spring boot:spring security整合jwt实现登录和权限验证(spring boot 2.3.3)
一,为什么使用jwt? 1,什么是jwt? Json Web Token, 它是JSON风格的轻量级的授权和身份认证规范, 可以实现无状态.分布式的Web应用授权 2,jwt的官网: https:// ...
- springBoot整合spring security+JWT实现单点登录与权限管理--筑基中期
写在前面 在前一篇文章当中,我们介绍了springBoot整合spring security单体应用版,在这篇文章当中,我将介绍springBoot整合spring secury+JWT实现单点登录与 ...
- 255.Spring Boot+Spring Security:使用md5加密
说明 (1)JDK版本:1.8 (2)Spring Boot 2.0.6 (3)Spring Security 5.0.9 (4)Spring Data JPA 2.0.11.RELEASE (5)h ...
- 【Spring Security】二、数据库管理用户权限
一 引入相关的jar包 这个例子用的是mysql数据库和c3p0开源的jdbc连接池,在项目的pom.xml中引入jar包 <!-- Mysql --> <dependency> ...
- Spring Security + JWT实现前后端分离权限认证
现在国内前后端很多公司都在使用前后端分离的开发方式,虽然也有很多人并不赞同前后端分离,比如以下这篇博客就很有意思: https://www.aliyun.com/jiaocheng/650661.ht ...
随机推荐
- HashMap、ConcurrentHashMap对比
1.hashmap的put的原理,hashmap的扩容及计算槽的算法,线程安全的hashtable.ConcurrentHashMap的区别是什么 1.1 hashMap的put原理 什么时候变成红黑 ...
- 『与善仁』Appium基础 — 21、元素的基本操作
目录 1.元素的基本操作说明 (1)点击操作 (2)清空操作 (3)输入操作 2.综合练习 1.元素的基本操作说明 (1)点击操作 点击操作:click()方法.(同Selenium中使用方式一致) ...
- DMA(Data Migration Assistant)迁移SQLServer数据库
DMA适用于 本地SQLServer向Azure SQL Database迁移 两台不同的数据库服务器之间迁移 高版本->低版本 或 低版本->高版本 本文以两台不同服务器的低版本(SQL ...
- 粒子群优化算法—Matlab
PSO算法 clc; clear ; close ; %% Problem Definition CostFunction = @(x) sphere(x); % Cost Function nVar ...
- [BUUCTF]PWN——ciscn_2019_ne_5
ciscn_2019_ne_5 题目附件 步骤: 例行检查,32位,开启了nx保护 试运行一下程序,看一下程序的大概执行情况 32位ida载入,shift+f12查看程序里的字符串,发现了flag字符 ...
- ORALE 误删表 Flashback 恢复表
昨天因为种种原因误删了很多表(160多个),一下炸了锅. 我知道影响很大,第一时间想到使用 Flashback 恢复过来.Flashback 听过很久,但是没真正上手过,恢复之后发现使用起来也很简单. ...
- YC-Framework版本更新:V1.0.3
分布式微服务框架:YC-Framework版本更新V1.0.3!!! 本次版本V1.0.3更新 集成分布式事务Seata: 集成分布式事务Tx-LCN: 集成Kafka: 集成RocketMQ: 集成 ...
- Solon 1.6.10 重要发布,现在有官网喽!
关于官网 千呼万唤始出来: https://solon.noear.org .整了一个月多了,总体样子有了...还得不断接着整! 关于 Solon Solon 是一个轻量级应用开发框架.支持 Web. ...
- c++设计模式概述之状态
代码写的不够规范,目的是为了缩短篇幅,实际中请不要这样做 参看:https://www.runoob.com/design-pattern/state-pattern.html 1.概述 这个有点抽象 ...
- 1678 lyk与gcd
1678 lyk与gcd 基准时间限制:2 秒 空间限制:131072 KB 这天,lyk又和gcd杠上了.它拥有一个n个数的数列,它想实现两种操作. 1:将 ai 改为b.2:给定一个数i,求所有 ...