上一篇:https://blog.csdn.net/LawssssCat/article/details/105065992
下一篇:https://lawsssscat.blog.csdn.net/article/details/105080690
Hello World
SpringBoot集成Spring Security入门体验
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
@RestController
public class IndexController {
@GetMapping("/index")
public String index() {
return "Hello World ~";
}
}
运行项目访问 http://127.0.0.1:8080/index
温馨小提示:在不进行任何配置的情况下,Spring Security 给出的默认用户名为
user
密码则是项目在启动运行时随机生成的一串字符串,会打印在控制台,如下图:
认证成功之后才会跳转到我们的index页面
配置用户密码
有很多方式,静态写死、从数据库中取、rest方式从第三方接口中取…
下面讲两种静态写死的方法
- 直接写在application.yml里
spring:
security:
user:
name: admin # 用户名
password: 123456 # 密码
或者
- 新建Security <mark>核心</mark> 配置类继承
WebSecurityConfigurerAdapter
(建议)
package com.example.securitydemo.config;
import org.apache.tomcat.util.security.MD5Encoder;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.MessageDigestPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/** * @author alan smith * @version 1.0 * @date 2020/3/24 15:36 */
@Configuration
// 启动 spring security 的 web 安全支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/** * 将用户设置在内存中 * * @param auth * @throws Exception */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 获取加密者
PasswordEncoder passwordEncoder = passwordEncoder();
// 在内存中写入用户信息
auth.inMemoryAuthentication()
// 指定加密方式
.passwordEncoder(passwordEncoder)
.withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
.and()
.withUser("test").password(passwordEncoder.encode("111111")).roles("USER");
}
private PasswordEncoder passwordEncoder() {
// return new MessageDigestPasswordEncoder("MD5")
// or
// BCryptPasswordEncoder: Spring Security 提供的加密工具,可快速实现加密加盐
return new BCryptPasswordEncoder();
}
}
admin/123456
访问并登录 localhost:8080/index (成功)
注意:因为没有指定默认的登录成功后转跳的地址,那么默认是
/
也是说,如果你 访问的是 localhost:8080/login
那么,登录成功后会转跳到 localhost:8080/ 地址(而这个地址我们没有定义,因此就报错了)
从数据库中获取用户账号、密码信息
这种方式也就是我们项目中通常使用的方式,这个留到 <mark>后面的文章再说</mark>
登录处理 与 忽略拦截
package com.example.securitydemo.controller;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
/** * @author alan smith * @version 1.0 * @date 2020/3/24 15:28 */
@RestController
public class IndexController {
@GetMapping("/index")
public String index() {
return "hello world";
}
@GetMapping("/home")
public String home() {
return "home";
}
@GetMapping("/getUserInfo")
public Object userInfo() {
return SecurityContextHolder.getContext();
}
}
【重点!】
修改 Security <mark>核心</mark> 类 ,重写 三个 configure 方法
package com.example.securitydemo.config;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.io.PrintWriter;
/** * {@link WebSecurityConfigurerAdapter}: * spring security 提供的 {@link WebSecurity} 适配器 * 一个帮我们实现了大部分{@link WebSecurityConfigurer}接口的抽象类 * <p> * 提供了可以重写的configure方法,在方法内可以装配自定义的Filter配置 * 其指定的Filter会被生产为{@link FilterChainProxy} * 最终以{@link DelegatingFilterProxy}作为spring Security Filter Chain起作用 * <p> * 即:其实现是用来配置spring Security Filter Chain的 * * @author alan smith * @version 1.0 * @date 2020/3/24 15:36 */
@Configuration
// 启动 spring security 的 web 安全支持
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
/** * 将用户设置在内存中 * * @param auth 封装认证授权管理器 * @throws Exception */
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 获取加密者
PasswordEncoder passwordEncoder = passwordEncoder();
// 在内存中写入用户信息
auth.inMemoryAuthentication()
// 指定加密方式
.passwordEncoder(passwordEncoder)
// 录入 admin 用户信息,自定义 ADMIN 权限
.withUser("admin").password(passwordEncoder.encode("123456")).roles("ADMIN")
.and()
// 录入 test 用户信息,自定义 USER 权限
.withUser("test").password(passwordEncoder.encode("111111")).roles("USER");
}
private PasswordEncoder passwordEncoder() {
// return new MessageDigestPasswordEncoder("MD5")
// or
// BCryptPasswordEncoder: Spring Security 提供的加密工具,可快速实现加密加盐
return new BCryptPasswordEncoder();
}
/** * 对Filter的配置 * * @param web 对web请求的封装,可以操作Filter * @throws Exception */
@Override
public void configure(WebSecurity web) throws Exception {
// 设置拦截忽略 url - 会直接过滤改url - 将不会经过 Spring Security 过滤器链
web
// 设置拦截忽略文件夹,请求 url 匹配则不拦截
.ignoring().antMatchers("/favicon.ico")
.and()
// 可以对静态资源放行
.ignoring().antMatchers("/css/**", "/js/**");
}
/** * 对FilterChain的配置 * * @param http 对http请求和响应的封装,可以操作FilterChain * @throws Exception */
@Override
protected void configure(HttpSecurity http) throws Exception {
// 开启登录匹配
http.authorizeRequests()
// 标识访问 '/index' 这个接口,需要具备 ADMIN 角色
.antMatchers("/index").hasRole("ADMIN")
// 设置可匿名匿名访问的标识
.antMatchers("/", "/home").permitAll()
// 其余所有请求都需要认证
.anyRequest().authenticated()
.and()
// 设置登录认证页面
.formLogin()
// 配置(自定义的)登录页面的 url
//.loginPage("/login")
// 自定义登录用户名和密码的属性名,默认为 username 和 password
.usernameParameter("username1")
.passwordParameter("password1")
// 登录后的(默认)转跳 - 方式1
.loginProcessingUrl("/home")
// 登录后的(默认)转跳 - 方式2
.successHandler((req, resp, authentication) -> {
//resp.sendRedirect("/home");
System.out.println(SecurityContextHolder.getContext());
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("登录成功...");
out.flush();
})
// 配置登录失败的回调 - 方式1
//.failureForwardUrl("/home")
// 配置登录失败的回调 - 方式2
.failureHandler((req, resp, exception) -> {
resp.setContentType("application/json;carset=utf-8");
PrintWriter out = resp.getWriter();
out.write("登录失败...");
out.flush();
})
// 和表单登录相关的接口统统都自接通过
.permitAll()
.and()
.logout()
.logoutUrl("/logout")
// 配置注销成功的回调
.logoutSuccessHandler((req, resp, authentication) -> {
resp.setContentType("application/json;charset=utf-8");
PrintWriter out = resp.getWriter();
out.write("注销成功...");
out.flush();
})
.permitAll()
.and()
// 开启 http basic 认证
.httpBasic()
.and()
// 关闭 csrf 跨域
.csrf().disable();
}
}
未登录
http://localhost:8080/home (无需登陆)
下面两个,都会转跳到 /login
页面
http://localhost:8080/getUserInfo (需登陆)
http://localhost:8080/index (ADMIN 权限)
admin/123456
登陆后
admin 登陆后
http://localhost:8080/index (ADMIN 权限)
http://localhost:8080/getUserInfo (需登陆)
http://localhost:8080/logout (登出)
test/111111
登陆
http://localhost:8080/getUserInfo (需登陆)
http://localhost:8080/index (ADMIN 权限)
【失败:因为当前账号不是 ADMIN 权限】
done
Github 下载