Spring Security进阶
Spring Security进阶
1.连接数据库进行数据的验证
Spring Security进行身份验证或者权限控制时,用户名和密码应该要和数据库的进行比较才行,用户的各种信息我们从数据库中去获取,不用自己在代码或者配置文件中写。
案例
1)创建项目
自己创建一个Maven项目
2)导入依赖
<parent>
<!--Spring boot-->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-parent</artifactId>
<version>2.0.6.RELEASE</version>
</parent>
<dependencies>
<!--Spring boot Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--Spring Security-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<!--数据库连接框架JPA-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
</dependencies>
3)创建启动类
@SpringBootApplication
public class SecurityApplication2 {
public static void main(String[] args) {
SpringApplication.run(SecurityApplication2.class, args);
}
}
4)配置文件
在项目的resources文件的目录下创建一个配置文件:application.properties
#连接数据库
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/你的数据库?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=用户名
spring.datasource.password=密码
#数据库表的生成
spring.jpa.generate-ddl=true
#显示执行的sql语句
spring.jpa.show-sql=true
#使用的数据库
spring.jpa.database=mysql
5)创建类
来创建一个实体层类、dao层接口、service层、控制层
实体类
//这个注解表示这个是实体类,对应数据库中的表,默认实体名就是类名
@Entity
public class UserInfo {
//这个属性的表中的主键
@Id
//主键的生成策略,IDENTITY 主键自增长
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//用户名
private String username;
//密码
private String password;
//角色
private String roles;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getRoles() {
return roles;
}
public void setRoles(String roles) {
this.roles = roles;
}
}
dao层接口
/*
* 继承JpaRepository<UserInfo,Long>接口,泛型一个是实体类,一个是主键类型
* */
public interface UserInfoDao extends JpaRepository<UserInfo,Long> {
//根据用户名查找用户
//(温馨提示:想要查找的话方法名要为 findBy属性字段 删除的话 deleteBy属性字段 ...以此类推这样才不报错)
UserInfo findByUsername(String username);
}
service层
public interface UserInfoService {
//根据用户名查找用户
UserInfo findByUsername(String username);
}
@Service
public class UserInfoServiceImpl implements UserInfoService {
@Autowired
private UserInfoDao userInfoDao;
//根据用户名返回用户
@Override
public UserInfo findByUsername(String username) {
UserInfo user = userInfoDao.findByUsername(username);
return user;
}
}
controller层
@RestController
@RequestMapping("/userInfo")
public class UserInfoController {
@RequestMapping("common")
//方法执行前验证用户是否有该角色
@PreAuthorize(value = "hasAnyRole('normal','admin')")
public String commonUserInfo() {
return "==测试数据库 有两个角色==";
}
@RequestMapping("admin")
//方法执行前验证是否有该角色
@PreAuthorize(value = "hasAnyRole('admin')")
public String adminUserInfo() {
return "==测试数据库 有一个角色==";
}
}
这些准备工作都做完之后,我们可以往数据库中插入一些数据,创建一个类,用来往数据库中添加数据的。
@Component
public class InitJdbc {
@Autowired
private UserInfoDao userInfoDao;
//Java自带的注解,程序启动的时候执行该方法,每启动一次执行一次,
//插入成功了,再启动项目的时候不想再重复插入,可以把@PostConstruct注释掉
@PostConstruct
public void init() {
//密码要加密
PasswordEncoder pe = new BCryptPasswordEncoder();
//添加一个用户
UserInfo userInfo = new UserInfo();
userInfo.setUsername("wangwu");
userInfo.setPassword(pe.encode("123456"));
userInfo.setRoles("normal");
userInfoDao.save(userInfo);
//添加一个用户
UserInfo userInfo1 = new UserInfo();
userInfo1.setUsername("admin");
userInfo1.setPassword(pe.encode("admin"));
userInfo1.setRoles("admin");
userInfoDao.save(userInfo1);
}
}
现在就可以启动项目看看数据库中是否插入成功数据了。
接下来做权限的验证==========
来写一个类,实现UserDetailService并实现它的方法
//把类交给spring容器管理
@Component
public class SecurityDetail implements UserDetailsService {
@Autowired
private UserInfoDao userInfoDao;
@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
UserInfo userInfo = null;
//UserDetails接口的实现类
User user = null;
//判断用户名不为空
if (s != null) {
//根据用户名查找用户
userInfo = userInfoDao.findByUsername(s);
//判断用户不为空
if (userInfo != null) {
//User类的第三个参数是集合,所有创建一个集合,获取用户的角色
List<GrantedAuthority> list = new ArrayList<>();
//获取用户的角色,获取到的角色开头一定要以"ROLE_"开头
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + userInfo.getRoles());
list.add(authority);
//User的构造器要返回三个参数:用户名、密码、集合的角色
user = new User(userInfo.getUsername(), userInfo.getPassword(), list);
}
}
return user;
}
}
再写一个配置类,解析密码的加密方式
@Configuration
@EnableWebSecurity
//开启方法级别的验证
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private SecurityDetail securityDetail;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//密码加密的方式
auth.userDetailsService(securityDetail).passwordEncoder(new BCryptPasswordEncoder());
}
}
现在可以进行测试了,启动项目,访问控制层的方法,只有方法上标记的角色才能访问该方法
2.认证和授权
authentication:认证,认证访问的用户是不是有效的用户,他是谁。
authorization:授权,访问的用户在系统中能干什么
RBAC:基于角色的访问控制(Role-Based Access Control),用户属于某个角色,而角色拥有某些权限。
权限:能对资源进行操作,比如增删改查
角色:自定义的,表示权限的聚合,一个角色可以有多个权限。
举例说明:
设计角色:经理具有数据的修改、删除、查看等;员工只能查看数据。
一个公司中如果想把一个用户设置为经理,只需把他设置为经理这个角色,他就能有修改、删除、查看等操作了,如果公司新来普通员工,只需把他加入到员工这个角色里面就好了。这样,想让什么用户用户什么权限,只需把他加入到相应的角色里就OK了。
UserDetailService:这是一个接口,里面只有一个方法UserDetails loadUserByUsername(String var1),是根据用户名来获取数据库中信息的
主要的实现有:
InMemoryUserDetailsManager在内存中维护用户信息的,使用很方便,可是数据不是持久的
JdbcUserDetailsManager对数据库信息进行操作的,底层是基于jdbcTemplate的,可以使用这个类的方法来操作数据库数据。
UserDetails:提供用户信息的核心接口
// 权限的集合
Collection<? extends GrantedAuthority> getAuthorities();
//获取密码
String getPassword();
//获取用户名
String getUsername();
//用户是否存在
boolean isAccountNonExpired();
//用户是否锁定
boolean isAccountNonLocked();
//证书是否过期
boolean isCredentialsNonExpired();
//账户是否启用
boolean isEnabled();
UserDetails有一个实现类User
//他有两个构造器,参数和UserDetails的字段属性一样
public User(String username, String password, Collection<? extends GrantedAuthority> authorities) {
this(username, password, true, true, true, true, authorities);
} public User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities) {
if (username != null && !"".equals(username) && password != null) {
this.username = username;
this.password = password;
this.enabled = enabled;
this.accountNonExpired = accountNonExpired;
this.credentialsNonExpired = credentialsNonExpired;
this.accountNonLocked = accountNonLocked;
this.authorities = Collections.unmodifiableSet(sortAuthorities(authorities));
} else {
throw new IllegalArgumentException("Cannot pass null or empty values to constructor");
}
}
2.1设置表
基于RBAC设置三张表,用户表,角色表,用户和角色的关联表 密码明文分别是 123 456 admin
-- 角色表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
`id` int(11) NOT NULL,
`rolename` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色名称',
`rolememo` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '角色描述',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_role
-- ----------------------------
INSERT INTO `sys_role` VALUES (1, 'USER', '普通用户');
INSERT INTO `sys_role` VALUES (2, 'READ', '只读');
INSERT INTO `sys_role` VALUES (3, 'ADMIN', '管理员');
SET FOREIGN_KEY_CHECKS = 1;
-- 用户表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`password` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,
`realname` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL COMMENT '真实名字',
`isenable` int(11) NULL DEFAULT NULL COMMENT '是否开启认证',
`islock` int(11) NULL DEFAULT NULL COMMENT '是否锁定',
`isexpire` int(11) NULL DEFAULT NULL,
`incredentials` int(255) NULL DEFAULT NULL COMMENT '是否过期',
`createtime` date NULL DEFAULT NULL,
`logintime` date NULL DEFAULT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB AUTO_INCREMENT = 9 CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user 密码明文分别是 123 456 admin
-- ----------------------------
INSERT INTO `sys_user` VALUES (6, 'zs', '$2a$10$EGMo2XSdh49cDgXa0OzXYu36HfNssUf7zUDaNIz83AgWveA3GORYq', '张三', 1, 1, 1, 1, '2021-09-02', '2021-09-02');
INSERT INTO `sys_user` VALUES (7, 'lisi', '$2a$10$r9iLBYZzIIt/gyOngvPnZOBZaP4EW58etU1tLPoEh7hlYpydIaM6u', '李四', 1, 1, 1, 1, '2021-09-02', '2021-09-02');
INSERT INTO `sys_user` VALUES (8, 'admin', '$2a$10$P.I3zf7bEAmLmlSwaDOdMOdrxEyTT1QvbqfKC5YGQ7zHk5zUR/dCG', '管理员', 1, 1, 1, 1, '2021-09-02', '2021-09-02');
SET FOREIGN_KEY_CHECKS = 1;
--关联表
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for sys_user_role
-- ----------------------------
DROP TABLE IF EXISTS `sys_user_role`;
CREATE TABLE `sys_user_role` (
`userid` int(11) NOT NULL,
`roleid` int(11) NULL DEFAULT NULL
) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Dynamic;
-- ----------------------------
-- Records of sys_user_role
-- ----------------------------
INSERT INTO `sys_user_role` VALUES (6, 1);
INSERT INTO `sys_user_role` VALUES (7, 2);
INSERT INTO `sys_user_role` VALUES (8, 1);
INSERT INTO `sys_user_role` VALUES (8, 3);
SET FOREIGN_KEY_CHECKS = 1;
2.2创建项目
2.3 导入依赖
把上一个项目的依赖导入进来,再加多一个spring整合mybatis的包
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.1.0</version>
</dependency>
2.4创建相关类
2.4.1实体类
创建User和Role的实体类,要继承UserDetails
public class SysUser implements UserDetails {
private Integer id;
private String username;
private String password;
private String realName;
private boolean isEnable;
private boolean isExpired;
private boolean isLock;
private boolean isCredentials;
private List<GrantedAuthority> grantedAuthorities;
private Date createTime;
private Date loginTime;
public SysUser() {
}
public SysUser(String username, String password, String realName,
boolean isEnable, boolean isExpired, boolean isLock,
boolean isCredentials, List<GrantedAuthority> grantedAuthorities,
Date createTime, Date loginTime) {
this.username = username;
this.password = password;
this.realName = realName;
this.isEnable = isEnable;
this.isExpired = isExpired;
this.isLock = isLock;
this.isCredentials = isCredentials;
this.grantedAuthorities = grantedAuthorities;
this.createTime = createTime;
this.loginTime = loginTime;
}
//角色的集合
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return grantedAuthorities;
}
//密码
@Override
public String getPassword() {
return password;
}
//用户名
@Override
public String getUsername() {
return username;
}
//账号是否存在
@Override
public boolean isAccountNonExpired() {
return isExpired;
}
//账号是否锁定
@Override
public boolean isAccountNonLocked() {
return isLock;
}
//是否过期
@Override
public boolean isCredentialsNonExpired() {
return isCredentials;
}
//是否启用
@Override
public boolean isEnabled() {
return isEnable;
}
public void setId(Integer id) {
this.id = id;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
public void setRealName(String realName) {
this.realName = realName;
}
public void setEnable(boolean enable) {
isEnable = enable;
}
public void setExpired(boolean expired) {
isExpired = expired;
}
public void setLock(boolean lock) {
isLock = lock;
}
public void setCredentials(boolean credentials) {
isCredentials = credentials;
}
public void setGrantedAuthorities(List<GrantedAuthority> grantedAuthorities) {
this.grantedAuthorities = grantedAuthorities;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
public void setLoginTime(Date loginTime) {
this.loginTime = loginTime;
}
public Integer getId() {
return id;
}
public String getRealName() {
return realName;
}
public Date getCreateTime() {
return createTime;
}
public Date getLoginTime() {
return loginTime;
}
@Override
public String toString() {
return "SysUser{" +
"id=" + id +
", username='" + username + '\'' +
", password='" + password + '\'' +
", realName='" + realName + '\'' +
", isEnable=" + isEnable +
", isExpired=" + isExpired +
", isLock=" + isLock +
", isCredentials=" + isCredentials +
", grantedAuthorities=" + grantedAuthorities +
", createTime=" + createTime +
", loginTime=" + loginTime +
'}';
}
}
public class SysRole {
private Integer id;
private String role;
private String rolememo;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
public String getRolememo() {
return rolememo;
}
public void setRolememo(String rolememo) {
this.rolememo = rolememo;
}
@Override
public String toString() {
return "SysRole{" +
"id=" + id +
", role='" + role + '\'' +
", rolememo='" + rolememo + '\'' +
'}';
}
}
2.4.2dao层和对应的xml文件
@Repository
public interface SysRoleMapper {
//根据用户id查看角色
List<SysRole> selectByUserId(Integer userId);
}
@Repository
public interface SysUserMapper {
//插入用户
int insertSysUser(SysUser sysUser);
//根据用户名查询用户
SysUser selectByUsername(String username);
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huang.security.mapper.SysRoleMapper">
<resultMap id="roleMapper" type="com.huang.security.entity.SysRole">
<id column="id" property="id"/>
<result column="rolename" property="role"/>
<result column="rolememo" property="rolememo"/>
</resultMap>
<select id="selectByUserId" resultMap="roleMapper" >
SELECT sr.id,sr.rolename,sr.rolememo FROM sys_role AS sr
INNER JOIN sys_user_role AS sur ON sr.id = sur.roleid
WHERE sur.userid = #{userid}
</select>
</mapper>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.huang.security.mapper.SysUserMapper">
<resultMap id="userMapper" type="com.huang.security.entity.SysUser">
<id column="id" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
<result column="realname" property="realName"/>
<result column="isenable" property="isEnable"/>
<result column="islock" property="isLock"/>
<result column="isexpire" property="isExpired"/>
<result column="incredentials" property="isCredentials"/>
<result column="createtime" property="createTime"/>
<result column="logintime" property="loginTime"/>
</resultMap>
<insert id="insertSysUser" parameterType="com.huang.security.entity.SysUser">
insert into sys_user(username,password,realname,isenable,islock,incredentials,createtime,logintime)
values(#{username},#{password},#{realName},#{isEnable},#{isLock},#{isCredentials},
#{createTime},#{loginTime})
</insert>
<select id="selectByUsername" resultMap="userMapper" >
select id,username,password,realname,isenable,islock,isexpire,incredentials,createtime,logintime
from sys_user where username = #{username}
</select>
</mapper>
2.5service层
service层要实现UserDetailService接口,去获取数据库中的信息做返回
@Service
public class UserWnoRoleService implements UserDetailsService {
@Autowired
private SysUserMapper userMapper;
@Autowired
private SysRoleMapper roleMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名获取用户
SysUser user = userMapper.selectByUsername(username);
System.out.println("==== Service =====");
String roleName = "";
List<GrantedAuthority> list = new ArrayList<>();
System.out.println("User" + user);
if (!StringUtils.isEmpty(user)) {
//根据用户id获取对应角色
List<SysRole> roles = roleMapper.selectByUserId(user.getId());
for (SysRole role : roles) {
//一个用户可能有多个角色,用集合保存,放到用户的集合里
roleName = role.getRole();
GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_" + roleName);
list.add(authority);
user.setGrantedAuthorities(list);
}
//返回的这个user是包含角色的
return user;
}
//可以返回自定义user,是因为实体类实现了UserDetails这个接口
return user;
}
}
2.6配置文件
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/库名?useUnicode=true&characterEncoding=utf-8&useSSL=false
spring.datasource.username=用户名
spring.datasource.password=密码
mybatis.mapper-locations=classpath:/mapper/*Mapper.xml
# 包起别名
mybatis.type-aliases-package=com.huang.security.entity
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
2.7相关的配置类
@Configuration
//@EnableWebSecurity //如果是导入的jar包是spring-boot-starter-security可以不用写
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
System.out.println("====== MySecurityConfig configure==============");
//匹配"/index","/login.html","/login" 不用验证(permit 许可),和登录相关的要放行
http.authorizeRequests().antMatchers("/index","/login.html","/login").permitAll()
//匹配只有相关角色才能访问的路径
.antMatchers("/access/user/**").hasRole("USER")
.antMatchers("/access/read/**").hasRole("READ")
.antMatchers("/access/admin/**").hasRole("ADMIN")
//所有都需要验证
.anyRequest().authenticated()
//执行结束
.and()
//表单的方式登录
.formLogin()
//登录的自定义视图页面
.loginPage("/login.html")
//登录访问的地址,表单中action的值
.loginProcessingUrl("/login")
.and()
//跨域安全的设置,禁用
.csrf().disable();
}
@Qualifier("userWnoRoleService")
@Autowired
private UserDetailsService userDetailsService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//super.configure(auth);
// userDetailsService使用的是service层的 UserWnoRoleService,它实现了 UserDetailsService
auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
2.8html页面
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
身份验证 <br>
<a href="/access/user">zs</a> <br>
<a href="/access/read">lisi</a> <br>
<a href="/access/admin">admin</a> <br>
<a href="/logout">退出</a>
</body>
</html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>自定义登录页</p>
<form action="/login" method="post">
用户名:<input type="text" name="username" value=""><br/>
密 码:<input type="password" name="password" value=""><br/>
<input type="submit" value="登录">
</form>
</body>
</html>
2.9controller层测试
@Controller
public class InitController {
@GetMapping("index")
public String toIndex() {
return "forward:/index.html";
}
}
@RestController
@RequestMapping("/access")
public class UserWnoRoleController {
@GetMapping("user")
public String sayUser() {
return "zs 是 user 角色";
}
@GetMapping("read")
public String sayRead() {
return "lisi 是 read 角色";
}
@GetMapping("admin")
public String sayAdmin() {
return "admin 是 user admin 角色";
}
}
个人笔记
Spring Security进阶的更多相关文章
- spring security进阶 使用数据库中的账户和密码认证
目录 spring security 使用数据库中的账户和密码认证 一.原理分析 二.代码实现 1.新建一个javaWeb工程 2.用户认证的实现 3.测试 三.总结 spring security ...
- spring security进阶2 添加账户并对账户密码进行加密
目录 spring security 添加账户并对账户密码进行加密 一.原理分析 1.1加密原理 1.2加密后的登录过程 二.代码实现 2.1添加用户的页面如下, register.html 2.2c ...
- spring security的BCryptPasswordEncoder加密和对密码验证的原理
目录 BCryptPasswordEncoder加密和对密码验证的原理 一.加密算法和hash算法的区别 二.源码解析 1. encode方法 2. BCrypt.hashpw方法 3. matche ...
- Spring Security框架进阶、自定义登录
1.Spring Security框架进阶 1.1 Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安 ...
- Spring Security实现OAuth2.0授权服务 - 进阶版
<Spring Security实现OAuth2.0授权服务 - 基础版>介绍了如何使用Spring Security实现OAuth2.0授权和资源保护,但是使用的都是Spring Sec ...
- Spring Security OAuth2.0 - AuthorizationServer和ResourceServer分离
<Spring Security实现OAuth2.0授权服务 - 基础版>和<Spring Security实现OAuth2.0授权服务 - 进阶版>两篇文章中介绍如何搭建OA ...
- Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战
一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...
- Spring Security OAuth2 开发指南
官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. 转载请注明来源:htt ...
- spring mvc 和spring security配置 web.xml设置
<?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmln ...
随机推荐
- Python - 基础数据类型 set 集合
集合的简介 集合是一个无序.不重复的序列 它的基本用法包括成员检测和消除重复元素 集合对象也支持像 联合,交集,差集,对称差分等数学运算 集合中所有的元素放在 {} 中间,并用逗号分开 集合的栗子 这 ...
- 🔥 LeetCode 热题 HOT 100(81-90)
337. 打家劫舍 III 思路:后序遍历 + 动态规划 推荐题解:树形 dp 入门问题(理解「无后效性」和「后序遍历」) /** * Definition for a binary tree nod ...
- 离线webpack创建vue 项目
参考地址: https://blog.csdn.net/feinifi/article/details/104578546 画重点: // 需要带上参数--offline表示离线初始化. --offl ...
- RHCSA_DAY10
分区过程 添加新硬盘--分区--格式化文件系统--挂载使用 扇区是磁盘存储数据的最小单元,默认一个扇区可以存储512字节的数据 磁盘类型介绍 IDE接口类型:主要用于个人家用计算机领域,优点价格便宜, ...
- C++ 1//设计立方体类 //创建立方体的类 //设计属性和行为 //获取立方体的面积和体积 //分别利用(全局函数 和 成员函数)判断俩个立方体是否相等
1 //设计立方体类 2 //创建立方体的类 3 //设计属性和行为 4 //获取立方体的面积和体积 5 //分别利用(全局函数 和 成员函数)判断俩个立方体是否相等 6 #include <i ...
- 第1篇-关于JVM运行时,开篇说的简单些
开讲Java运行时,这一篇讲一些简单的内容.我们写的主类中的main()方法是如何被Java虚拟机调用到的?在Java类中的一些方法会被由C/C++编写的HotSpot虚拟机的C/C++函数调用,不过 ...
- Special Forms and Syntax Sugars in Clojure
(...): function literals, p40, 64; '(...): suppress evaluation, p24; _(...): comments, p18; ".. ...
- git submodule 操作
git submodule foreach git status 举一反三,对所有子库的操作,都可以使用 git submodule foreach 做前缀 foreach,可以记忆为for each ...
- Woc,考场(面试)忘记打平衡树怎么办,Trie救你命
Woc,考场(面试)忘记打平衡树怎么办,Trie救你命 文本只发布于博客园,其他地方出现本文均是未经许可的盗版. 算法导入 众所周知平衡树很难打(大佬除外),还老是调错.万一这种事情发生在关键时刻你就 ...
- JVM学习笔记-第七章-虚拟机类加载机制
JVM学习笔记-第七章-虚拟机类加载机制 7.1 概述 Java虚拟机描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这个过程被 ...