Spring Security入门级使用(示例)
软硬件环境:
- jdk1.8
- IntelliJIdea
- SpringBoot2.2.1.RELEASE
- SpringSecurity5.2.1RELEASE
声明: 本文主要示例入门级SpringSecurity,对其理论知识不作深入分析。
准备工作:提供以下API,以供之后的演示。
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
/**
* 用于测试的controller层
*
* @author JustryDeng
* @date 2019/11/26 10:05
*/
@Slf4j
@RestController
public class DemoController {
/**
* 未登录就可访问的页面
*
* 注: 用于.permitAll()测试。
*/
@GetMapping("/hello")
public String hello() {
return "hello 靓仔~";
}
/**
* 首页(登录成功后跳转至此页)
*
* 注:默认的,表单登录 登录成功时, 是以POST重定向至登陆成功页的,所以这里至少要支持POST请求。
*/
@RequestMapping(value = "/index", method = {RequestMethod.GET, RequestMethod.POST})
public String home() {
return "欢迎来到index~";
}
/**
* 登录失败页
*/
@GetMapping("/login/failed")
public String error() {
return "登录失败~";
}
/**
* 登出成功页
*/
@GetMapping("/logout/success")
public String logout() {
return "您已成功退出~";
}
/**
* 鉴权失败页
*/
@GetMapping("/403")
public String forbidden() {
return "小伙~你的权限不够~";
}
@GetMapping("/user")
public String user() {
return "普通用户~";
}
@GetMapping("/dba")
public String dba() {
return "数据库DBA~";
}
@GetMapping("/admin")
public String admin() {
return "超级管理员~";
}
}
Spring Security的入门级使用(示例):
第一步:在pom.xml中引入依赖。
<!-- spring security -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
第二步:使用@EnableWebSecurity注解,启用WebSecurity。
第三步:自定义一个MyWebSecurityConfigurerAdapter类,继承WebSecurityConfigurerAdapter,自定义相关配置。
提示一: 这里主要以图片的形式进行说明,MyWebSecurityConfigurerAdapter类文字版的完整代码在本文末给出。
提示二: WebSecurityConfigurerAdapter类中,configure(AuthenticationManagerBuilder auth)方法、configure(HttpSecurity http)方法以及configure(WebSecurity web)方法相对常用,下面对这三个方法进行简单说明并重写示例。
-
第一小步(可选): 重写configure(WebSecurity web)方法。
- 此方法相关的部分配置说明(未显示父类方法):
- (简单)示例:
@Override public void configure(WebSecurity web) { /* * 对于那些没必要进行保护的资源, 可以使用ignoring,使其跳过SpringSecurity * * 注:configure(HttpSecurity http)方法里的permitAll();也有类似的效果, * 不过permitAll会走SpringSecurity,只是说无条件放行而已。 */ web.ignoring().antMatchers("/picture/**"); web.ignoring().antMatchers("/md/**"); // 开发时,可以将SpringSecurity的debug打开 web.debug(true); }
- 此方法相关的部分配置说明(未显示父类方法):
-
第二小步: 重写configure(HttpSecurity http)方法。
-
此方法相关的部分配置说明(未显示父类方法):
-
(简单的自定义鉴权配置)示例:
/** * SpringSecurity提供有一些基本的页面(如:login、logout等);如果觉得它提供的 * 基础页面难看,想使用自己的页面的话,可以在此方法里面进行相关配置。 */ @Override protected void configure(HttpSecurity http) throws Exception { // 访问 匹配以下ant的url不需要(非匿名)认证、不需要鉴权 http.authorizeRequests().antMatchers("/login", "/logout", "/logout/success", "/403", "/hello").permitAll(); // 只要认证通过,就可访问匹配以下ant的url。 (不论这人的权限是什么) http.authorizeRequests().antMatchers("/index").authenticated(); /* * 访问 匹配以下ant的url时, 需要至少有一个角色 "USER", "ADMIN" (需要鉴权) * * 注:[鉴权] 这个动作里面就隐含[认证]了, 因为只有认证后,才能拿到权限信息,才能进行鉴权; * 如果连认证都没过的话,鉴权自然会失败。 */ http.authorizeRequests().antMatchers("/user").hasAnyRole("USER", "ADMIN", "abc"); // 访问 匹配以下ant的url时, 需要至少有一个角色 "DBA", "ADMIN" (需要鉴权) http.authorizeRequests().antMatchers("/dba").hasAnyRole("DBA", "ADMIN"); // 访问 匹配以下ant的url时, 需要有角色 "ADMIN" (需要鉴权) http.authorizeRequests().antMatchers("/admin").hasRole("ADMIN"); /* * 设置任何请求都需要认证(除了前面.permitAll()的)。 * * 注:如果不设置此项的话,那么对于那些未作任何配置的URL, 那么是默认 不认证、不鉴权的 */ http.authorizeRequests().anyRequest().authenticated(); // 设置登录方式为 表单登录 http.formLogin(); /// 设置登录方式为 弹框登录 /// http.httpBasic(); /// 自定义登录页 /// http.formLogin().loginPage("myLoginPae"); /// 自定义登出页 /// http.logout().logoutUrl("myLogoutPae"); // 登出成功时,跳转至此url http.logout().logoutSuccessUrl("/logout/success"); // 登录成功时,跳转至此url // 注意:如果未登录,直接访问 登录失败页的话,会被DefaultLoginPageGeneratingFilter识别,并跳转至登录页进行登录 http.formLogin().successForwardUrl("/index"); // 登录失败时,跳转至此url // 注意:如果未登录,直接访问 登录失败页的话,会被DefaultLoginPageGeneratingFilter识别,并跳转至登录页进行登录 http.formLogin().failureUrl("/login/failed"); /// 当鉴权不通过,是 跳转至此url http.exceptionHandling().accessDeniedPage("/403"); }
注:上面代码中权限配置相关的方法,只示例了部分,完整的有:
-
-
第三小步: 重写configure(AuthenticationManagerBuilder auth)方法。
-
此方法相关的部分配置说明(未显示父类方法):
-
(配置几个用户,进行简单)示例:
@Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 配置几个用户 auth.inMemoryAuthentication().withUser("user").password("user123").roles("USER"); auth.inMemoryAuthentication().withUser("dba").password("dba123").roles("DBA"); auth.inMemoryAuthentication().withUser("admin").password("admin123").roles("ADMIN"); // 配置这个用户的目的,是为了说明: 角色名瞎**起都可以 auth.inMemoryAuthentication().withUser("other").password("other123").roles("abc", "DBA"); }
注:角色名的定义并没有什么要求,瞎**写都可以。
-
第四步:注册一个自定义的PasswordEncoder,用于登录时密码比对。
提示: 本人这里为了快速简单演示,自定义了一个非常简单的PasswordEncoder实现;实际上,SpringSecurity对PasswordEncoder提供有大量实现,在实际开发时,如无特殊需求,完全可以使用SpringSecurity提供的PasswordEncoder实现类。
/**
* 自定义 加密器
*
* 注:只需要将其注册进入容器中即可,InitializeUserDetailsBeanManagerConfigurer类会从容器
* 拿去PasswordEncoder.class实现,作为其加密器
*
* @date 2019/12/21 17:59
*/
@Bean
public PasswordEncoder myPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword == null ? "" : rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (rawPassword == null || rawPassword.length() == 0) {
return false;
}
return rawPassword.equals(encodedPassword);
}
};
}
启动项目,测试一下:
测试流程:
- 先访问/hello,能访问(证明permitAll生效)。
- 任意访问一个页面,会被转到登录页,进行登录。
- 登录成功,跳转至index(证明successForwardUrl("/index")生效)。
- 分别访问"/user"、"/dba"、"/admin"。发现自己有对应的角色才能访问进去,否者跳转至403页面(证明相关鉴权配置生效)。
- 登出,成功后,页面跳转至"/logout/success"(证明logoutSuccessUrl("/logout/success")生效)。
测试user用户:
测试dba用户:
测试admin用户:
测试other用户:
注:创建这个other用户,主要是为了说明,角色名瞎**起都可以(比如此用户就有一个名为abc的角色)。
给出MyWebSecurityConfigurerAdapter类完整版:
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* SpringSecurity配置
*
* @author JustryDeng
* @date 2019/12/7 14:08
*/
@Configuration
public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
@Override
public void configure(WebSecurity web) {
/*
* 对于那些没必要进行保护的资源, 可以使用ignoring,使其跳过SpringSecurity
*
* 注:configure(HttpSecurity http)方法里的permitAll();也有类似的效果,
* 不过permitAll会走SpringSecurity,只是说无条件放行而已。
*/
web.ignoring().antMatchers("/picture/**");
web.ignoring().antMatchers("/md/**");
// 开发时,可以将SpringSecurity的debug打开
web.debug(true);
}
/**
* SpringSecurity提供有一些基本的页面(如:login、logout等);如果觉得它提供的
* 基础页面难看,想使用自己的页面的话,可以在此方法里面进行相关配置。
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
// 访问 匹配以下ant的url不需要(非匿名)认证、不需要鉴权
http.authorizeRequests().antMatchers("/login", "/logout", "/logout/success", "/403", "/hello").permitAll();
// 只要认证通过,就可访问匹配以下ant的url。 (不论这人的权限是什么)
http.authorizeRequests().antMatchers("/index").authenticated();
/*
* 访问 匹配以下ant的url时, 需要至少有一个角色 "USER", "ADMIN" (需要鉴权)
*
* 注:[鉴权] 这个动作里面就隐含[认证]了, 因为只有认证后,才能拿到权限信息,才能进行鉴权;
* 如果连认证都没过的话,鉴权自然会失败。
*/
http.authorizeRequests().antMatchers("/user").hasAnyRole("USER", "ADMIN", "abc");
// 访问 匹配以下ant的url时, 需要至少有一个角色 "DBA", "ADMIN" (需要鉴权)
http.authorizeRequests().antMatchers("/dba").hasAnyRole("DBA", "ADMIN");
// 访问 匹配以下ant的url时, 需要有角色 "ADMIN" (需要鉴权)
http.authorizeRequests().antMatchers("/admin").hasRole("ADMIN");
/*
* 设置任何请求都需要认证(除了前面.permitAll()的)。
*
* 注:如果不设置此项的话,那么对于那些未作任何配置的URL, 那么是默认 不认证、不鉴权的
*/
http.authorizeRequests().anyRequest().authenticated();
// 设置登录方式为 表单登录
http.formLogin();
/// 设置登录方式为 弹框登录
/// http.httpBasic();
/// 自定义登录页
/// http.formLogin().loginPage("myLoginPae");
/// 自定义登出页
/// http.logout().logoutUrl("myLogoutPae");
// 登出成功时,跳转至此url
http.logout().logoutSuccessUrl("/logout/success");
// 登录成功时,跳转至此url
// 注意:如果未登录,直接访问 登录失败页的话,会被DefaultLoginPageGeneratingFilter识别,并跳转至登录页进行登录
http.formLogin().successForwardUrl("/index");
// 登录失败时,跳转至此url
// 注意:如果未登录,直接访问 登录失败页的话,会被DefaultLoginPageGeneratingFilter识别,并跳转至登录页进行登录
http.formLogin().failureUrl("/login/failed");
/// 当鉴权不通过,是 跳转至此url
http.exceptionHandling().accessDeniedPage("/403");
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
// 配置几个用户
auth.inMemoryAuthentication().withUser("user").password("user123").roles("USER");
auth.inMemoryAuthentication().withUser("dba").password("dba123").roles("DBA");
auth.inMemoryAuthentication().withUser("admin").password("admin123").roles("ADMIN");
// 配置这个用户的目的,是为了说明: 角色名瞎**起都可以
auth.inMemoryAuthentication().withUser("other").password("other123").roles("abc", "DBA");
}
/**
* 自定义 加密器
*
* 注:只需要将其注册进入容器中即可,InitializeUserDetailsBeanManagerConfigurer类会从容器
* 拿去PasswordEncoder.class实现,作为其加密器
*
* @date 2019/12/21 17:59
*/
@Bean
public PasswordEncoder myPasswordEncoder() {
return new PasswordEncoder() {
@Override
public String encode(CharSequence rawPassword) {
return rawPassword == null ? "" : rawPassword.toString();
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
if (rawPassword == null || rawPassword.length() == 0) {
return false;
}
return rawPassword.equals(encodedPassword);
}
};
}
}
入门级Spring Security学习完毕 !
^_^ 如有不当之处,欢迎指正
^_^ 参考资料
《SpringSecurity5.2.1RELEASE源码》
^_^ 测试代码托管链接
https://github.com/JustryDeng…SpringSecurity…
^_^ 本文已经被收录进《程序员成长笔记(六)》,笔者JustryDeng
推荐阅读
-
Spring Security入门级使用(示例)
-
Spring Security中使用注解进行用户授权
-
spring security 使用自定义AuthenticationFailureHandler无法跳转failureUrl
-
Spring Security的使用
-
Spring Security的使用
-
Spring Security使用数据库中的用户进行身份认证
-
spring-boot整合spring-security,Swagger使用spring-security认证
-
Java的Spring框架中DAO数据访问对象的使用示例
-
Java的Spring框架中DAO数据访问对象的使用示例
-
Java的Spring框架中DAO数据访问对象的使用示例