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/>
密&nbsp;&nbsp;&nbsp;码:<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进阶的更多相关文章

  1. spring security进阶 使用数据库中的账户和密码认证

    目录 spring security 使用数据库中的账户和密码认证 一.原理分析 二.代码实现 1.新建一个javaWeb工程 2.用户认证的实现 3.测试 三.总结 spring security ...

  2. spring security进阶2 添加账户并对账户密码进行加密

    目录 spring security 添加账户并对账户密码进行加密 一.原理分析 1.1加密原理 1.2加密后的登录过程 二.代码实现 2.1添加用户的页面如下, register.html 2.2c ...

  3. spring security的BCryptPasswordEncoder加密和对密码验证的原理

    目录 BCryptPasswordEncoder加密和对密码验证的原理 一.加密算法和hash算法的区别 二.源码解析 1. encode方法 2. BCrypt.hashpw方法 3. matche ...

  4. Spring Security框架进阶、自定义登录

      1.Spring Security框架进阶 1.1 Spring Security简介 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安 ...

  5. Spring Security实现OAuth2.0授权服务 - 进阶版

    <Spring Security实现OAuth2.0授权服务 - 基础版>介绍了如何使用Spring Security实现OAuth2.0授权和资源保护,但是使用的都是Spring Sec ...

  6. Spring Security OAuth2.0 - AuthorizationServer和ResourceServer分离

    <Spring Security实现OAuth2.0授权服务 - 基础版>和<Spring Security实现OAuth2.0授权服务 - 进阶版>两篇文章中介绍如何搭建OA ...

  7. Spring Security OAuth2 微服务认证中心自定义授权模式扩展以及常见登录认证场景下的应用实战

    一. 前言 [APP 移动端]Spring Security OAuth2 手机短信验证码模式 [微信小程序]Spring Security OAuth2 微信授权模式 [管理系统]Spring Se ...

  8. Spring Security OAuth2 开发指南

    官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. 转载请注明来源:htt ...

  9. spring mvc 和spring security配置 web.xml设置

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns="http://xmln ...

随机推荐

  1. HttpRunner3源码阅读: 1. 目录结构分析

    初衷 身处软件测试行业的各位应该都有耳闻HttpRunner 开源测试工具/框架(接口测试),作者博客 为什么出这系列? 不少测试同行都建议阅读HttpRunner,源码学习其设计思想. 社区当下Py ...

  2. 论文笔记:(CVPR2019)PointWeb: Enhancing Local Neighborhood Features for Point Cloud Processing

    目录 摘要 一.引言 二.相关工作 3D数据表示 点云深度学习 三.我们的方法 3.1 自适应特征调整(AFA)模块 3.1.1 影响函数fimp 3.1.2 关系函数frel 3.1.3 逐元素影响 ...

  3. SQL语句(二)数据排序和单行函数

    目录 一.排序查询 1. 基本排序 2. 多条件排序 二.单行函数 调用方法 字符函数 ①LENGTH函数 ②CONCAT函数 ③upper 和 lower ④substr ⑤instr ⑥trim ...

  4. docker版LAMP(PHP+MYSQL+APACHE)配置

    最近在搭测试环境,一开始就在vagant和docker之间来回折腾.两者其实都非常适合用来搭开发环境:但最终让我决定用Docker的原因是因为Vagant在hyper-v下出现了一些奇怪的问题,所以D ...

  5. 大厂Android岗高频面试问题:说说你对Zygote的理解!

    前言 Zygote可以说是Android开发面试很高频的一道问题,但总有小伙伴在回答这道问题总不能让面试满意, 在这你就要搞清楚面试问你对Zygote的理解时,面试官最想听到的和其实想问的应该是哪些? ...

  6. 高楼扔鸡蛋问题(鹰蛋问题) POJ-3783

    这是一道经典的DP模板题. https://vjudge.net/problem/POJ-3783#author=Herlo 一开始也是不知道咋写,尝试找了很多博客,感觉有点领悟之后写下自己的理解. ...

  7. Git出错:“Please make sure you have the correct access rights and the repository exists.”

    此问题是需要重置ssh密钥 解决步骤如下: 1.重置用户名和邮箱: 打开Git Bash 进入Git命令,输入以下命令 git config --global user.name "你的用户 ...

  8. 模拟退火 Simulated annealing

    模拟退火 Simulated annealing 看看有空把图片完善一下好了 模拟退火算法的一些背景 既然要说模拟退火算法,就应该说一下模拟退火算法的背景,模拟退火算法是局部搜索算法的一种扩展,该算法 ...

  9. [06 Go语言基础-包]

    [06 Go语言基础-包] 包 什么是包,为什么使用包? 到目前为止,我们看到的 Go 程序都只有一个文件,文件里包含一个 main 函数和几个其他的函数.在实际中,这种把所有源代码编写在一个文件的方 ...

  10. 使用POI把查询到的数据表数据导出到Excel中,一个表一个sheet.最详细!!!

    一.需求 我们会遇到开发任务: 经理:小王,你来做一下把数据库里的数据导出到Excel中,一个表是一个sheet,不要一个表一个Excel. 小王:好的,经理.(内心一脸懵逼) 二.前期准备 首先我们 ...