Security之基础篇
1、功能实现
创建内存用户,进行登录
访问权限接口
2、security01 子工程
<?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>com.yzm</groupId><artifactId>security</artifactId><version>0.0.1-SNAPSHOT</version><relativePath>../pom.xml</relativePath> <!-- lookup parent from repository --></parent><artifactId>security01</artifactId><version>0.0.1-SNAPSHOT</version><packaging>jar</packaging><name>security01</name><description>Demo project for Spring Boot</description><dependencies><dependency><groupId>com.yzm</groupId><artifactId>common</artifactId><version>0.0.1-SNAPSHOT</version></dependency></dependencies><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build></project>
由于还没有用到数据库,启动类 exclude 数据库自动配置,以免启动报错
package com.yzm.security01;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)
public class Security01Application {public static void main(String[] args) {SpringApplication.run(Security01Application.class, args);}
}
3、SecurityConfig 配置类
package com.yzm.security01.config;import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;@Slf4j
@Configuration
@EnableWebSecurity // 开启 Security 服务
public class SecurityConfig extends WebSecurityConfigurerAdapter {/*** 密码编码器* passwordEncoder.encode是用来加密的,passwordEncoder.matches是用来解密的*/@Beanpublic PasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}/*** 配置用户,这里是创建内存用户*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 从内存创建用户auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder().encode("123456"))// 基于内存创建的用户不能同时使用roles和authorities,如果同时使用只有后面的生效,这个坑.roles("ADMIN", "USER")//.authorities("select", "delete").and().withUser("yzm").password(passwordEncoder().encode("123456")).roles("USER")//.authorities("select");}/*** http安全配置*/@Overrideprotected void configure(HttpSecurity http) throws Exception {http// 关闭CSRF跨域.csrf().disable()// 默认登录.formLogin().permitAll().and()// 退出登录.logout().permitAll().and()// 访问路径URL的授权策略,如注册、登录免登录认证等.authorizeRequests().antMatchers("/home", "/").permitAll() //指定url放行.antMatchers("/user/**").hasAnyRole("ADMIN", "USER") // 需要角色(二选一).antMatchers("/admin/**").hasRole("ADMIN") // 需要角色.anyRequest().authenticated() //其他任何请求都需要身份认证.and();}
}
4、访问接口
package com.yzm.security01.controller;import com.alibaba.fastjson.JSONObject;
import com.yzm.common.entity.HttpResult;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.annotation.AuthenticationPrincipal;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;@Controller
public class HomeController {@GetMapping(value = {"/", "/home"})public Object home() {return "home";}@GetMapping("/hello")@ResponseBodypublic Object hello() {return "hello";}// 通过authentication或userDetails获取当前登录用户信息+@GetMapping(value = {"/user", "/admin"})@ResponseBodypublic String info(Authentication authentication, @AuthenticationPrincipal UserDetails userDetails) {System.out.println("authentication :");System.out.println(JSONObject.toJSONString(authentication, true));System.out.println("userDetails :");System.out.println(JSONObject.toJSONString(userDetails, true));return "请求成功";}@GetMapping(value = {"/user/select", "/admin/select"})@ResponseBodypublic Object select() {return "Select";}@GetMapping(value = {"/user/create", "/admin/create"})@ResponseBodypublic Object create() {return "Create";}@GetMapping(value = {"/user/update", "/admin/update"})@ResponseBodypublic Object update() {return "Update";}@GetMapping(value = {"/user/delete", "/admin/delete"})@ResponseBodypublic Object delete() {return "Delete";}
}
5、首页,访问链接,便于测试
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head><meta charset="UTF-8"><title>首页</title>
</head>
<body>
<h2><a href="/hello"> hello </a>
</h2><h3>user</h3>
<h4><a href="/user">User角色</a>
</h4>
<p><a href="/user/select">User角色,拥有 select 权限</a></p>
<p><a href="/user/create">User角色,拥有 create 权限</a></p>
<p><a href="/user/update">User角色,拥有 update 权限</a></p>
<p><a href="/user/delete">User角色,拥有 delete 权限</a></p><h3>admin</h3>
<h4><a href="/admin">Admin角色</a>
</h4>
<p><a href="/admin/select">Admin角色,拥有 select 权限</a></p>
<p><a href="/admin/create">Admin角色,拥有 create 权限</a></p>
<p><a href="/admin/update">Admin角色,拥有 update 权限</a></p>
<p><a href="/admin/delete">Admin角色,拥有 delete 权限</a></p>
</body>
</html>
6、测试 roles 权限
拥有用户:
admin --> ADMIN、USER
yzm --> USER
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {// 从内存创建用户auth.inMemoryAuthentication().withUser("admin")// 密码需要加密,不加就提示错误.password(passwordEncoder().encode("123456"))// 基于内存创建的用户不能同时使用roles和authorities,如果同时使用只有后面的生效,这个坑.roles("ADMIN", "USER")//.authorities("select", "delete").and().withUser("yzm").password(passwordEncoder().encode("123456")).roles("USER")//.authorities("select");}
启动项目 访问 / 或 /home 首页接口,由于是放行的,所以可以访问
点击 hello 跳转到Security默认提供的登录页面
.authorizeRequests().antMatchers("/home", "/").permitAll() //指定url放行.antMatchers("/user/**").hasAnyRole("ADMIN", "USER") // 需要角色(二选一).antMatchers("/admin/**").hasRole("ADMIN") // 需要角色.anyRequest().authenticated() //其他任何请求都需要身份认证.and()
在前面我们没有拦截/hello,它走的是需要认证 即.anyRequest().authenticated()
没有认证的请求,默认转发到 /login
开始登录yzm
登录成功之后,继续之前的 /hello 请求
如果我们创建内存用户不是使用加密的,而是直接明文
把.password(passwordEncoder().encode(“123456”)) 改成 .password(“123456”)
那么我们点击登录,就会提示下面的错误
提示 Encoded password does not look like BCrypt (密码没有加密)
回到首页,此时登录用户:yzm,能访问部分接口
点击 user角色 可以查看当前登录的用户信息
authentication :
{"authenticated":true,"authorities":[{"authority":"user:select"}],"details":{"remoteAddress":"0:0:0:0:0:0:0:1","sessionId":"20A8546453B14E0C3B066A8150B44B9D"},"name":"yzm","principal":{"accountNonExpired":true,"accountNonLocked":true,"authorities":[{"$ref":"$.authorities[0]"}],"credentialsNonExpired":true,"enabled":true,"username":"yzm"}
}
userDetails :
{"accountNonExpired":true,"accountNonLocked":true,"authorities":[{"authority":"user:select"}],"credentialsNonExpired":true,"enabled":true,"username":"yzm"
}
Authentication 用户认证对象 ,内容比较多并且包含了 UserDetails信息
UserDetails 用户详情对象
访问 localhost:8080/logout 退出登录
登录admin,admin有双重身份,可以访问所有的接口
7、测试 authorities 权限
admin --> admin:select、admin:delete
yzm --> user:select
@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.inMemoryAuthentication().withUser("admin").password(passwordEncoder().encode("123456"))// 基于内存创建的用户不能同时使用roles和authorities,如果同时使用只有后面的生效,这个坑//.roles("ADMIN", "USER").authorities("admin:select", "admin:delete").and().withUser("yzm").password(passwordEncoder().encode("123456"))//.roles("USER").authorities("user:select");}@Overrideprotected void configure(HttpSecurity http) throws Exception {http....antMatchers("/user/select").hasAuthority("user:select") // 需要权限.antMatchers("/user/delete").hasAuthority("user:delete").antMatchers("/admin/select").hasAuthority("admin:select").antMatchers("/admin/delete").hasAnyAuthority("admin:delete", "admin:remove") // 需要权限(二选一).anyRequest().authenticated() //其他任何请求都需要身份认证.and();}
重启项目
8、问题
.withUser("admin")// 密码需要加密,不加就提示错误.password(passwordEncoder().encode("123456"))// 基于内存创建的用户不能同时使用roles和authorities,如果同时使用只有后面的生效,这个坑//.roles("ADMIN", "USER").authorities("admin:select", "admin:delete")
在上面的代码中 roles() 跟 authorities() 能不能同时设置?
可以同时设置,但只有最后设置的那个有效,后面设置的会替换掉前面设置的
我们可以看下它们的实现
public UserDetailsManagerConfigurer<B, C>.UserDetailsBuilder roles(String... roles) {this.user.roles(roles);return this;}public UserDetailsManagerConfigurer<B, C>.UserDetailsBuilder authorities(GrantedAuthority... authorities) {this.user.authorities(authorities);return this;}
public UserBuilder roles(String... roles) {List<GrantedAuthority> authorities = new ArrayList<>(roles.length);for (String role : roles) {Assert.isTrue(!role.startsWith("ROLE_"),() -> role + " cannot start with ROLE_ (it is automatically added)");authorities.add(new SimpleGrantedAuthority("ROLE_" + role));}// roles最后是调用authorities()方法的return authorities(authorities);}public UserBuilder authorities(GrantedAuthority... authorities) {return authorities(Arrays.asList(authorities));}public UserBuilder authorities(Collection<? extends GrantedAuthority> authorities) {this.authorities = new ArrayList<>(authorities);return this;}
可以看到roles和authorities最后都是给authorities赋值,使用户拥有对应的角色权限
所以我们一般设置一个就可以了
相关链接
首页
下一篇:入门篇
Security之基础篇相关推荐
- 鸟哥的Linux私房菜(基础篇)- 第二十六章、Linux 核心编译与管理
第二十六章.Linux核心编译与管理 最近升级日期:2009/09/18 我们说的 Linux 其实指的就是核心 (kernel) 而已.这个核心控制你主机的所有硬件并提供系统所有的功能,所以说,他重 ...
- 鸟哥的Linux私房菜(基础篇)- 第十八章、认识系统服务 (daemons)
第十八章.认识系统服务 (daemons) 最近升级日期:2009/09/14 在 Unix-Like 的系统中,你会常常听到 daemon 这个字眼!那么什么是传说中的 daemon呢?这些 dae ...
- SpringSecurity - 基础篇
文章目录 一.SpringSecurity能做什么 二.SpringSecurity替代方案 三.权限管理中的相关概念 四.SpringSecurity 入门案例 前言:通常我们写http接口是不会用 ...
- 重温《数据库系统概论》【第一篇 基础篇】【第1章 绪论】
时隔两年,重温数据库,再次学习人大教授王珊.萨师煊的<数据库系统概论>,别有一番滋味在心头,或许这就是软件"不归路"上的感悟吧,又一次打开课本,记忆犹新,在已经学习过大 ...
- Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛
Nginx实战基础篇六 通过源码包编译安装部署LNMP搭建Discuz论坛 版权声明: 本文遵循"署名非商业性使用相同方式共享 2.5 中国大陆"协议 您可以自由复制.发行.展览. ...
- 尚硅谷docker基础篇 2018版
typora-root-url: ./image Docker基础篇之快速上手 第一章 Docker简介 是什么? 问题:为什么会有 docker 的出现 一款产品从开发到上线,从操作系统,到运行环境 ...
- 一文搞懂AWS EC2, IGW, RT, NAT, SG 基础篇下
B站实操视频更新 跟着拉面学习AWS--EC2, IGW, RT, NAT, SG 简介 长文多图预警,看结论可以直接拖到"总结"部分 本文承接上一篇文章介绍以下 AWS 基础概念 ...
- 最全MySQL基础篇
文章目录 导入表的问题 第三章_最基本的SELECT语句 1. SQL语言的规则和规范 1) 基本规则 2) SQL大小写规范(建议遵守) 3) 注释 4) 命名规则 2. 基本的SELECT语句 1 ...
- SpringBoot【基础篇】
SpringBoot2[基础篇] 官方网址:https://spring.io/projects/spring-boot#learn 文章目录 SpringBoot2[基础篇] 第一章:springb ...
最新文章
- php判断数组不重复的元素,php从数组中随机选择若干不重复元素
- tar xvf实现的是什么功能呢?
- php 打开报错,php模式下 运行start.php 报错
- 哎哟我去!betterzip居然支持这么多压缩格式!
- Spring AOP切面的时候参数的传递
- 主线科技完成A轮融资,蔚来资本、普洛斯隐山资本联合领投
- 【NLP】 理解NLP中网红特征抽取器Tranformer
- 奎屯电信助力智慧城市光网建设
- Iterator 遍历器的简单使用
- Idea 设置Eclipse快捷键(常用)
- [Leetcode][第98 450 700 701题][JAVA][二叉搜索树的合法性、增、删、查][递归][深度遍历]
- 面试-重写基础功能函数
- 厦门大学计算机学硕复试,【图片】一战厦大计算机上岸,经验帖。慢更【考研吧】_百度贴吧...
- [转]JDK动态代理
- 华为手机明年全面升级鸿蒙OS:其实两年前就能用
- Mac 下载破译版本 secureFX 和 secureCRT
- 用python计算方程的根_Python程序计算ax^2+bx+c=0方程根
- Go原生插件使用问题全解析
- hackthebox - blunder (Bludit渗透cewl使用 sudo提权)
- 【Linux性能分析】火焰图(Flame Graphs)的安装和基本用法