@

1. Spring Security

Spring Security 是 Spring 家族中的一个安全管理框架,应用程序的两个主要区域是“认证”和“授权”(或者访问控制)。Spring Security是针对Spring项目的安全框架,也是Spring Boot底层安全模块默认的技术选型

这两个主要区域是Spring Security 的两个目标。

  • “认证”(Authentication),是建立一个他声明的主体的过程(一

    个“主体”一般是指用户,设备或一些可以在你的应用程序中执行动

    作的其他系统)。
  • “授权”(Authorization)指确定一个主体是否允许在你的应用程序

    执行一个动作的过程。为了抵达需要授权的店,主体的身份已经有认

    证过程建立。

2. 实验环境准备

环境准备:

  • JDK 1.8
  • SpringBoot2.2.1
  • Maven 3.2+
  • 开发工具
    • IntelliJ IDEA
    • smartGit

创建一个SpringBoot Initialize项目,详情可以参考我之前博客:SpringBoot系列之快速创建项目教程



新建项目后,检查一下spring-boot-starter-security场景启动器是否配置成功,不需要写版本

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>

SpringBoot有版本仲裁机制,SpringBoot2.2.1的spring-boot-starter-security依赖的Spring security版本是5.2.1的

3. 日志级别修改

配置Spring Security日志级别,默认是info的,可以修改为debug

## logback配置
logging:
level:
org:
springframework:
security: info

4. 配置用户名/密码

随便写个接口,访问时候,就会跳到如下图的登录页面,为什么?我们只是引入maven配置而已,然后账号密码是什么?其实这个是Spring Security的默认登录页面,页面代码是在jar包里的,默认的username是user,密码是随机生成的uuid格式的密码



密码会在控制台打印,根据线索,找到自动配置类



要修改默认密码,可以新建application.yml配置文件,加上如下配置

## spring security配置
spring:
security:
user:
name: nicky
password: 123

也可以新建Spring Security配置类,注意Spring Security5.2.1版本,配置密码要用BCryptPasswordEncoder加密,不过登录还是明文,Spring Security不同版本各有差别,详情配置还是参考官方文档

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception { //auth.inMemoryAuthentication()
auth.inMemoryAuthentication()
.withUser("nicky")
.password(bcryptPasswordEncoder().encode("123"))
.roles("admin");
} @Bean
public PasswordEncoder bcryptPasswordEncoder() {
return new BCryptPasswordEncoder();
}
}
加密方式 security 4 security 5
bcrypt password {bcrypt}password
ldap password {ldap}password
MD4 password {MD4}password
MD5 password {MD5}password
noop password {noop}password
pbkdf2 password {pbkdf2}password
scrypt password {scrypt}password
SHA-1 password {SHA-1}password
SHA-256 password {SHA-256}password
sha256 password {sha256}password

5. 数据库方式校验

拓展:如果要数据库方式校验用户名密码,可以自定义UserDetailsService方式:

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new CustomPasswordEncoder());
auth.parentAuthenticationManager(authenticationManagerBean()); }

UserDetailsServiceImpl.java

package com.example.springboot.oauth2.service;

import com.example.springboot.oauth2.entity.User;
import com.example.springboot.oauth2.mapper.UserMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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.Arrays;
import java.util.List; /**
* <pre>
*
* </pre>
*
* <pre>
* @author mazq
* 修改记录
* 修改后版本: 修改人: 修改日期: 2020/04/30 15:15 修改内容:
* </pre>
*/
@Slf4j
@Service("userService")
public class UserDetailsServiceImpl implements UserDetailsService { @Autowired
UserMapper userRepository; @Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = userRepository.findByUsername(username);
if(user == null){
log.info("登录用户[{}]没注册!",username);
throw new UsernameNotFoundException("登录用户["+username + "]没注册!");
}
return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), getAuthority());
} private List getAuthority() {
return Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN"));
// return Arrays.asList(Collections.emptyList());
}
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http // 配置登录页并允许访问
.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login").permitAll()
// 配置Basic登录
//.and().httpBasic()
// 配置登出页面
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
// 开放接口访问权限,不需要登录授权就可以访问
.and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()
// api接口需要admin管理员才能访问
.antMatchers("/api/**").hasRole("admin")
// 其余所有请求全部需要鉴权认证
.anyRequest().authenticated()
// 关闭跨域保护;
.and().csrf().disable();
}

6. 不拦截静态资源

配置文件,加上配置

@Override
public void configure(WebSecurity web) throws Exception {
//解决静态资源被拦截的问题
web.ignoring().antMatchers("/asserts/**");
web.ignoring().antMatchers("/favicon.ico");
}

7. 自定义登录页面

引入Thymeleaf模板引擎:

<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>

关闭Thymeleaf模板引擎缓存,方便F9自动编译

spring:
thymeleaf:
cache: false

写个login接口,注意一定要GET方式,POST方式是Spring Security默认的校验接口,接口名称也是/login

@Controller
public class LoginController { @GetMapping(value = {"/login"})
public ModelAndView toLogin() {
return new ModelAndView("login");
}
}

自定义登录页面,要用post方式,除非你自己写个校验接口,POST /login是Spring Security官方的校验接口,默认用户名参数为username,密码参数为password:

<!DOCTYPE html>
<html lang="zh" xmlns:th="http://www.thymeleaf.org">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="description" content="" />
<meta name="author" content="" />
<title>Signin Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link href="../static/asserts/css/bootstrap.min.css" th:href="@{asserts/css/bootstrap.min.css}" rel="stylesheet" />
<!-- Custom styles for this template -->
<link href="../static/asserts/css/signin.css" th:href="@{asserts/css/signin.css}" rel="stylesheet"/>
</head> <body class="text-center">
<form class="form-signin" th:action="@{/login}" method="post">
<img class="mb-4" th:src="@{asserts/img/bootstrap-solid.svg}" alt="" width="72" height="72" />
<h1 class="h3 mb-3 font-weight-normal" >Oauth2.0 Login</h1>
<label class="sr-only" >Username</label>
<input type="text" class="form-control" name="username" required="" autofocus="" value="nicky" />
<label class="sr-only" >Password</label>
<input type="password" class="form-control" name="password" required="" value="123" />
<div class="checkbox mb-3">
<label>
<input type="checkbox" value="remember-me" /> remember me
</label>
</div>
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
<p class="mt-5 mb-3 text-muted"> 2019</p>
</form> </body> </html>

修改配置文件,.loginPage("/login")指定自定义的登录页面

 @Override
protected void configure(HttpSecurity http) throws Exception {
http // 配置登录页并允许访问
.formLogin().usernameParameter("username").passwordParameter("password").loginPage("/login").permitAll()
// 配置Basic登录
//.and().httpBasic()
// 配置登出页面
.and().logout().logoutUrl("/logout").logoutSuccessUrl("/")
// 开放接口访问权限,不需要登录授权就可以访问
.and().authorizeRequests().antMatchers("/oauth/**", "/login/**", "/logout/**").permitAll()
// api接口需要admin管理员才能访问
.antMatchers("/api/**").hasRole("admin")
// 其余所有请求全部需要鉴权认证
.anyRequest().authenticated()
// 关闭跨域保护;
.and().csrf().disable();
}

8. Remember me

开启记住我功能,登陆成功以后,将cookie发给浏览器保存,以后访问页面带上这个cookie,只要通过检查就可以免登录

@Override
protected void configure(HttpSecurity http) throws Exception {
//开启记住我功能,登陆成功以后,将cookie发给浏览器保存,以后访问页面带上这个cookie,只要通过检查就可以免登录
http.rememberMe().rememberMeParameter("remeber"); }

ok,Spring Security的知识点比较多,详情请参考官方文档,本博客参考官方文档,做了简单记录,仅仅作为入门参考手册

代码例子下载:code download

最新文章

  1. LinqToDB 源码分析——生成表达式树
  2. 攻城记:Thinkphp框架的项目规划总结和踩坑经验
  3. Dijkstra算法优先队列实现与Bellman_Ford队列实现的理解
  4. 关于页面查询多数据查询问题(foreach)
  5. POJ 1258 Agri-Net(最小生成树 Prim+Kruskal)
  6. C语言语法之关键字
  7. andorid service 本地服务
  8. paip.输入法编程---词库多意义条目分割 python实现.
  9. 网页flv下载探索_1
  10. jQuery 判断所有图片加载完成
  11. Google翻译,3个步骤灭绝人类
  12. easyui实现datagrid数字排序问题
  13. Update关联查询不走索引,效率低下
  14. Python反序列化 pickle
  15. jQuery(八)、ajax
  16. shiro授权及自定义realm授权(七)
  17. vuex数据持久化存储
  18. python中RabbitMQ的使用(远程过程调用RPC)
  19. android 覆盖安装问题
  20. javascript解析器原理

热门文章

  1. Day11-微信小程序实战-交友小程序-附近的人(地图的形式)及位置获取
  2. Flask02-Template
  3. 入门大数据---PySpark
  4. xshell界面变成半透明的怎么办?
  5. navicat连接vagrant中的数据库
  6. 「从零单排canal 04」 启动模块deployer源码解析
  7. 四维DP之方格取数
  8. 数组中出现次数超过一半的数字(剑指offer-28)
  9. 数据可视化实例(九): 边缘箱形图(matplotlib,pandas)
  10. C与lua交互--lua调用栈分析(2)