SpringSecurity
作用:做登陆【认证】和授权的
代码位置:E:\010-SpringSecurity\002-springsecurity-thymeleaf
进入移动互联网时代,大家每天都在刷手机,常用的软件有微信、支付宝、头条等,下边拿微信来举例子说明认证相关的基本概念,在初次使用微信前需要注册成为微信用户,然后输入账号和密码即可登录微信,输入账号和密码登录微信的过程就是****认证****。
系统为什么要认证?
http://127.0.0.1:8080/getAllUser
http://127.0.0.1:8080/addUser
http://127.0.0.1:8080/updateUser
http://127.0.0.1:8080/deleteUser
认证是为了保护系统的隐私数据与资源,用户的身份合法方可访问该系统的资源。
认证 :*用户认证就是判断一个用户的身份是否合法的过程*,用户去访问系统资源(url接口)时系统要求验证用户的身份信息,身份合法方可继续访问,不合法则拒绝访问。常见的用户身份认证方式有:用户名密码登录,二维码登录,手机短信登录,指纹认证等方式。
官网: https://spring.io/projects/spring-security
中文文档: https://www.springcloud.cc/spring-security.html

Spring Security是一个能够为基于Spring的企业应用系统提供****声明式*****(注解)的安全访问控制解决方案的安全框架*。它提供了一组可以在Spring应用上下文中配置的Bean,充分利用了Spring IoC,DI(控制反转Inversion of Control ,DI:Dependency Injection 依赖注入)和AOP(面向切面编程)功能,为应用系统提供声明式的安全访问控制功能,减少了为企业系统安全控制编写大量重复代码的工作。
以上解释来源于百度百科。可以一句话来概括,SpringSecurity 是一个安全框架。
创建springboot 项目 添加依赖 springsecurity

启动类
@SpringBootApplication
@EnableWebSecurity // 启动security 5.0后 默认开启,可以不写
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
@RestController
public class HelloController {
@GetMapping("hello")
public String hello() {
return "hello security";
}
}
http://127.0.0.1:8080/hello
发现我们无法访问hello这个请求,这是因为spring Security默认拦截了所有请求

使用user+启动日志里面的密码登陆

登录后就可以访问我们的hello了
访问: http://localhost:8080/logout

也可以在配置文件配置登录账号和密码
spring:
security:
user:
name: admin #默认使用的用户名
password: 123456 #默认使用的密码
我们在HelloController中创建
/*两种获取 用的认证后的信息*/
@RequestMapping("/getUserInfo")
public Principal getUserInfo(Principal principal){
return principal;
}
/*推荐使用 */
@RequestMapping("/getUserInfo2")
public Object getUserInfo2(){
/*从安全上下文中获取 用户 认证对象(用户信息)*/
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
Object principal = authentication.getPrincipal();
return principal;
// Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// return authentication;
获取到一串json字符串

重写两个方法 configure(AuthenticationManagerBuilder auth) 和configure(HttpSecurity http)
package com.powernode.config;
@Configuration //创建认证配置类 继承 WebSecurityConfigurerAdapter
public class SecurityConfig extends WebSecurityConfigurerAdapter {
//重写 configure 方法
/*配置多用户*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// super.configure(auth);
/*配置在内存中的 账号密码 不配置可能会配置不成功*/
auth.inMemoryAuthentication()
.withUser("admin")//账号
.password(passwordEncoder().encode("123456"))//密码,使用加密器转码
.roles("ADMIN")//角色,权限
.authorities("sys:add","sys:delete","sys:update","sys:query","sys:export")//权限,(好比 给人钥匙)
.and()
.withUser("test")
.password(passwordEncoder().encode("123456"))
.roles("TEST")
.authorities("sys:add","sys:query")
.and()
.withUser("powernode")
.password(passwordEncoder().encode("123456"))
.roles("VIP")
;
}
/*http请求配置 给请求加权限, 没有加权限的都可以访问 无权限默认访问error目录下的403.html*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);// 不使用父类的 方法, 需要 提供登录配置
http.formLogin().successForwardUrl("/welcome").failureForwardUrl("/fail");
/*设置 资源所需要的 权限 (好比 门上锁)*/
http.authorizeRequests()
//匹配资源与权限 资源 权限(角色)
.antMatchers("/add").hasAnyAuthority("sys:add")
.antMatchers("/delete").hasAnyAuthority("sys:delete")
.antMatchers("/update").hasAnyAuthority("sys:update")
.antMatchers("/select").hasAnyAuthority("sys:query")
.antMatchers("/export").hasAnyAuthority("sys:export")
//给 父路径下 其所有资源 配置 权限 (觉得)
.antMatchers("/vip/**").hasRole("VIP")
;
}
/*强制要求配置 密码加密器*/
@Bean// 将对象 交给 spring容器 管理
public PasswordEncoder passwordEncoder() {
// return NoOpPasswordEncoder.getInstance();//不加密
return new BCryptPasswordEncoder();
}
/*测试加密器*/
public static void main(String[] args) {
BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
/*加密*/
String encode1 = passwordEncoder.encode("123456");
String encode2 = passwordEncoder.encode("123456");
String encode3 = passwordEncoder.encode("123456");
/*每次 加密的结果不一样*/
System.out.println(encode1);
System.out.println(encode2);
System.out.println(encode3);
/*解密:匹配 密码是否一致 不能 使用 equals方法*/
System.out.println(passwordEncoder.matches("123456", encode1));
System.out.println(passwordEncoder.matches("123456", encode2));
System.out.println(passwordEncoder.matches("123456", encode3));
}
}
只需要在controller对应的方法上添加注解即可了,不需要再webSecurityConfig中配置匹配的url和权限了,这样就爽多了
*@PreAuthorize 在方法调用前进行权限检查*
@PostAuthorize 在方法调用后进行权限检查
上面的两个注解如果要使用的话必须加上
*@EnableGlobalMethodSecurity(prePostEnabled = true)*

controller 层

/*
没有权限处理器
* */
@Component
public class AppAccessDeniedHandler implements AccessDeniedHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException e) throws IOException, ServletException {
System.out.println("没有权限");
/*设置响应编码 放置乱码*/
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
/*创建统一返回类型对象*/
Result result = new Result();
result.setCode(403);
result.setMsg("没有权限");
/*将 result 转换为 json数据*/
String json = objectMapper.writeValueAsString(result);
/*响应json数据*/
PrintWriter writer = response.getWriter();
writer.write(json);
writer.flush();
}
}
/*登录失败处理器*/
@Component
public class AppAuthenticationFailureHandler implements AuthenticationFailureHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
System.out.println("登录失败");
/*设置响应编码 放置乱码*/
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
/*创建统一返回类型对象*/
Result result = new Result();
result.setCode(-1);
result.setMsg("登录失败");
if (e instanceof BadCredentialsException) {
result.setData("失败原因:密码不正确");
} else if (e instanceof DisabledException) {
result.setData("失败原因:账号被禁用");
} else if (e instanceof UsernameNotFoundException) {
result.setData("失败原因:查无此账号");
} else if (e instanceof CredentialsExpiredException) {
result.setData("失败原因:密码过期");
} else if (e instanceof AccountExpiredException) {
result.setData("失败原因:账号过期");
} else if (e instanceof LockedException) {
result.setData("失败原因:账号被锁定");
}
/*将 result 转换为 json数据*/
String json = objectMapper.writeValueAsString(result);
/*响应json数据*/
PrintWriter writer = response.getWriter();
writer.write(json);
writer.flush();
}
}
/*
* 自定义的 登录成功处理器 直接返回json数据
* */
@Component
public class AppAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
/**
* @param request 请求对象
* @param response 响应对象
* @param authentication 认证对象(用户信息)
* @throws IOException
* @throws ServletException
*/
@Override
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("登录成功");
/*设置响应编码 放置乱码*/
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
/*创建统一返回类型对象*/
Result result = new Result();
result.setCode(200);
result.setMsg("登录成功");
result.setData(authentication);//只是为了显示 用户信息 实际情况不会返回
/*将 result 转换为 json数据*/
String json = objectMapper.writeValueAsString(result);
/*响应json数据*/
PrintWriter writer = response.getWriter();
writer.write(json);
writer.flush();
}
}
/*登出成功处理器*/
@Component
public class AppLogoutSuccessHandler implements LogoutSuccessHandler {
@Autowired
private ObjectMapper objectMapper;
@Override
public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
System.out.println("登出成功");
/*设置响应编码 放置乱码*/
response.setCharacterEncoding("UTF-8");
response.setContentType("text/html;charset=utf-8");
/*创建统一返回类型对象*/
Result result = new Result();
result.setCode(200);
result.setMsg("登出成功");
result.setData(authentication);//只是为了显示 用户信息 实际情况不会返回
/*将 result 转换为 json数据*/
String json = objectMapper.writeValueAsString(result);
/*响应json数据*/
PrintWriter writer = response.getWriter();
writer.write(json);
writer.flush();
}
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/*注入 登录成功处理器*/
@Autowired
private AppAuthenticationSuccessHandler appAuthenticationSuccessHandler;
/*注入 登录 失败处理器*/
@Autowired
private AppAuthenticationFailureHandler appAuthenticationFailureHandler;
/*注入 没有权限处理器*/
@Autowired
private AppAccessDeniedHandler appAccessDeniedHandler;
/*注入 登出成功处理器*/
@Autowired
private AppLogoutSuccessHandler appLogoutSuccessHandler;
@Autowired
private AppUserDetailsService appUserDetailsService;
//验证码拦截器注入
@Autowired
private ValidateCodeFilter validateCodeFilter;
/*配置多用户*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(appUserDetailsService);
}
/*http请求配置*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// super.configure(http);// 不使用父类的 方法, 需要 提供登录配置
/*没权权限的处理*/
// http.exceptionHandling().accessDeniedHandler(appAccessDeniedHandler);
/*登录*/
// 配置登录之前添加一个验证码的过滤器
http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class);
http.formLogin()
.usernameParameter("uname")//页面表单账号的参数名 默认 为 username
.passwordParameter("pwd")//页面表单密码的参数名 默认 为 password
.loginPage("/index/toLogin")//定义登录页面的 请求 地址(转发到登录页面)
.loginProcessingUrl("/login/doLogin")// 表单提交的 地址(不需要提供),登录验证.....
.successForwardUrl("/index/toIndex")//登录成功 跳转的路径
.failureForwardUrl("/index/toLogin")//登录失败 跳转的路径
// .successHandler(appAuthenticationSuccessHandler)//登录成功处理器
// .failureHandler(appAuthenticationFailureHandler)//登录失败处理器
.permitAll();
;
/*登出*/
http.logout()
.logoutUrl("/logout")//登出的 请求地址
.logoutSuccessUrl("/index/toLogin")//登出成功后 访问的路径
// .logoutSuccessHandler(appLogoutSuccessHandler)//登出成功处理器
.permitAll()
;
/*设置 资源所需要的 权限 (好比 门上锁)*/
http.authorizeRequests()
.antMatchers("/code/img")// 放行验证码的路径
// .mvcMatchers("/index/toLogin", "/index.html").permitAll()//不需要认证就可以访问
.permitAll()
.anyRequest().authenticated()//所有请求都需要登录认证 才能进行
;
/*禁用csrf跨域请求攻击 如果不禁用 自定义的登录页面无法登录*/
http.csrf().disable();
}
/*资源服务匹配放行:静态资源*/
@Override
public void configure(WebSecurity web) throws Exception {
// super.configure(web);
web.ignoring().antMatchers("/css/**");
}
/*强制要求配置 密码加密器*/
@Bean// 将对象 交给 spring容器 管理
public PasswordEncoder passwordEncoder() {
// return NoOpPasswordEncoder.getInstance();//不加密
return new BCryptPasswordEncoder();
}
}
/*
* 自定义认证
*
* */
@Component
public class AppUserDetailsService implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
private SysUserDao sysUserDao;
/**
* @param username 用户输入的 账号
* @return 用户信息(账号密码 权限,是否过期等 方法)
* @throws UsernameNotFoundException 没有账号会抛该异常类型
*/
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
/*通过账号查询用户*/
SysUser sysUser = sysUserDao.queryUserByUsername(username);
if (sysUser == null) {
throw new UsernameNotFoundException("用户名不存在");
}
/*根据用户的id 获取用户的 权限字符串 集合*/
List<String> permissions = sysUserDao.queryPermissionByUserId(sysUser.getUserId());
/*将 字符串集合 转换为 权限对象集合*/
List<SimpleGrantedAuthority> authorities = new ArrayList<>();
for (String permission : permissions) {
/*根据权限字符串 生成 对应的 权限对象*/
authorities.add(new SimpleGrantedAuthority(permission));
}
/*将权限集合封装到 user对象中*/
sysUser.setPermissions(authorities);
return sysUser;
}
}
/**
* (SysUser)实体类
* 实现序列化接口和 UserDetails接口
*
* @author makejava
* @since 2022-10-25 15:32:59
*/
public class SysUser implements Serializable, UserDetails {
private static final long serialVersionUID = -54448691274655158L;
/**
* 编号
*/
private Integer userId;
/**
* 登陆名
*/
private String username;
/**
* 密码
*/
private String password;
/**
* 性别
*/
private String sex;
/**
* 地址
*/
private String address;
/**
* 是否启动账户0禁用 1启用
*/
private Integer enabled;
/**
* 账户是否没有过期0已过期 1 正常
*/
private Integer accountNoExpired;
/**
* 密码是否没有过期0已过期 1 正常
*/
private Integer credentialsNoExpired;
/**
* 账户是否没有锁定0已锁定 1 正常
*/
private Integer accountNoLocked;
public Integer getUserId() {
return userId;
}
public void setUserId(Integer userId) {
this.userId = userId;
}
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 getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Integer getEnabled() {
return enabled;
}
public void setEnabled(Integer enabled) {
this.enabled = enabled;
}
public Integer getAccountNoExpired() {
return accountNoExpired;
}
public void setAccountNoExpired(Integer accountNoExpired) {
this.accountNoExpired = accountNoExpired;
}
public Integer getCredentialsNoExpired() {
return credentialsNoExpired;
}
public void setCredentialsNoExpired(Integer credentialsNoExpired) {
this.credentialsNoExpired = credentialsNoExpired;
}
public Integer getAccountNoLocked() {
return accountNoLocked;
}
public void setAccountNoLocked(Integer accountNoLocked) {
this.accountNoLocked = accountNoLocked;
}
@Override//是1返回true 不是就返回false
public boolean isAccountNonExpired() {
return accountNoExpired.equals(1);
}
@Override
public boolean isAccountNonLocked() {
return accountNoLocked.equals(1);
}
@Override
public boolean isCredentialsNonExpired() {
return credentialsNoExpired.equals(1);
}
@Override
public boolean isEnabled() {
return enabled.equals(1);
}
/*权限集合*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return permissions;
}
/*封装权限集合*/
private List<SimpleGrantedAuthority> permissions = new ArrayList<>();
public List<SimpleGrantedAuthority> getPermissions() {
return permissions;
}
public void setPermissions(List<SimpleGrantedAuthority> permissions) {
this.permissions = permissions;
}
}
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
在Ruby中是否有Gem或安全删除文件的方法?我想避免系统上可能不存在的外部程序。“安全删除”指的是覆盖文件内容。 最佳答案 如果您使用的是*nix,一个很好的方法是使用exec/open3/open4调用shred:`shred-fxuz#{filename}`http://www.gnu.org/s/coreutils/manual/html_node/shred-invocation.html检查这个类似的帖子:Writingafileshredderinpythonorruby?
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我正在使用ruby2.1.0我有一个json文件。例如:test.json{"item":[{"apple":1},{"banana":2}]}用YAML.load加载这个文件安全吗?YAML.load(File.read('test.json'))我正在尝试加载一个json或yaml格式的文件。 最佳答案 YAML可以加载JSONYAML.load('{"something":"test","other":4}')=>{"something"=>"test","other"=>4}JSON将无法加载YAML。JSON.load("
默认情况下:回形针gem将所有附件存储在公共(public)目录中。出于安全原因,我不想将附件存储在公共(public)目录中,所以我将它们保存在应用程序根目录的uploads目录中:classPost我没有指定url选项,因为我不希望每个图像附件都有一个url。如果指定了url:那么拥有该url的任何人都可以访问该图像。这是不安全的。在user#show页面中:我想实际显示图像。如果我使用所有回形针默认设置,那么我可以这样做,因为图像将在公共(public)目录中并且图像将具有一个url:Someimage:看来,如果我将图像附件保存在公共(public)目录之外并且不指定url(同
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
我在一个ruby文件中有一个函数可以像这样写入一个文件File.open("myfile",'a'){|f|f.puts("#{sometext}")}这个函数在不同的线程中被调用,使得像上面这样的文件写入不是线程安全的。有谁知道如何以最简单的方式使这个文件写入线程安全?更多信息:如果重要的话,我正在使用rspec框架。 最佳答案 您可以通过File#flock给锁File.open("myfile",'a'){|f|f.flock(File::LOCK_EX)f.puts("#{sometext}")}
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于StackOverflow来说是偏离主题的,因为它们往往会吸引自以为是的答案和垃圾邮件。相反,describetheproblem以及迄今为止为解决该问题所做的工作。关闭8年前。Improvethisquestion我需要实现具有各种灵活需求的密码安全。这些要求基本上取自Sanspasswordpolicy:Strongpasswordshavethefollowingcharacteristics:Containatleastthreeofthe
安全产品安全网关类防火墙Firewall防火墙防火墙主要用于边界安全防护的权限控制和安全域的划分。防火墙•信息安全的防护系统,依照特定的规则,允许或是限制传输的数据通过。防火墙是一个由软件和硬件设备组合而成,在内外网之间、专网与公网之间的界面上构成的保护屏障。下一代防火墙•下一代防火墙,NextGenerationFirewall,简称NGFirewall,是一款可以全面应对应用层威胁的高性能防火墙,提供网络层应用层一体化安全防护。生产厂家•联想网御、CheckPoint、深信服、网康、天融信、华为、H3C等防火墙部署部署于内、外网编辑额,用于权限访问控制和安全域划分。UTM统一威胁管理(Un
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全