SpringSecurity
SpringSecurity
官网 : //spring.io/guides/topicals/spring-security-architecture/
- 需要对 Spring IOC 和 AOP 有了解
Spring Security 安全框架,目的解决系统安全,不再需要手动处理每一个资源的访问控制
应用程序安全性可以归结为或多或少的两个独立问题:身份验证(您是谁)和授权(您可以做什么?)。
- 身份认证
身份验证的主要策略界面是AuthenticationManager,它只有一种方法:
public interface AuthenticationManager {
Authentication authenticate(Authentication authentication)
throws AuthenticationException;
}
- 授权(访问控制)
创建demo 项目
- 创建一个包含 Spring Security 的 SpringBoot 工程
<dependencies>
<!-- Spring Security 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<!--Spring Web 依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
- 在 resources/static 目录下创建 login.html文件
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
用户名 : <input type="text" name="username"/><br/>
用户密码 : <input type="password" name="password"/><br/>
<input type="submit"value="登录">
</form>
</body>
</html>
- 登录成功,跳转到 success.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Success</title>
</head>
<body>
<p style="align-content: center"> 登录成功</p>
</body>
</html>
- 登录失败,跳转到 failure.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Error</title>
</head>
<body>
<p style="align-content: center"> 登录失败,<a href="/login.html">请重新登录</a></p>
</body>
</html>
- 编写 LoginController
package com.yuanhy.springsecuritydemo;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
/**
* @author yuanhy
* @date 2020-12-13 12:23
*/
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(){
return "redirect:success.html";
}
}
- 启动 demo
package com.yuanhy.springsecuritydemo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class SpringSecurityDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringSecurityDemoApplication.class, args);
}
}
- 输入 ://localhost:8080/login.html ,出现如下页面,这是Spring Security 自带默认

-
在控制台可以看到生成的密码 :Using generated security password: 43b54d71-3861-4d48-8301-47b691d4222a(每次启动都不一样) ,登录名为 user
输入用户和密码后,跳到我们自定义的 login.html 页面

在不做任何配置的基础上,启动 Web 项目,访问我们的 login.html 资源时,首先会跳转到 Spring Security 内置的登录页面,使用 Spring Security 提供的 用户 user 和自动生成的密码登录成功才可以访问我们的资源
UserDetailsService
用户自定义登录逻辑
获取判断登录信息的主要方法,返回 UserDetails ,找不到返回异常 UsernameNotFoundException
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
UserDetails :通过这些方法获取判断信息
Collection<? extends GrantedAuthority> getAuthorities();
String getPassword();
String getUsername();
boolean isAccountNonExpired();
boolean isAccountNonLocked();
boolean isCredentialsNonExpired();
boolean isEnabled();
User,UserDetails 的子类 ,主要是这个子类完成操作。
public class User implements UserDetails, CredentialsContainer
PasswordEncoder 密码解析器,推荐子类 BCryptPasswordEncoder 对密码进行加密匹配
public interface PasswordEncoder {
String encode(CharSequence var1);
boolean matches(CharSequence var1, String var2);
default boolean upgradeEncoding(String encodedPassword) {
return false;
}
}
public class BCryptPasswordEncoder implements PasswordEncoder
测试例子
@Test
public void testBCryptPasswordEncoder(){
BCryptPasswordEncoder bCryptPasswordEncoder = new BCryptPasswordEncoder();
//加密密码
String encode = bCryptPasswordEncoder.encode("123");
System.out.println("加密后密码 : "+encode);
//匹配密码
boolean matches = bCryptPasswordEncoder.matches("123", encode);
System.out.println("匹配是否成功 ;"+(matches?"成功":"失败"));
Assertions.assertTrue(matches);
}
自定义登录逻辑
需要使用到接口 UserDetailsService、PasswordEncoder 以及它们的子类
Spring Security 要求:在进行自定义登录逻辑时容器内必须有 PasswordEncoder 实例,所以不能直接 new 一个对象,通过一个配置文件来注册 bean ,让 Spring 去管理
SecurityConfig
package com.yuanhy.springsecuritydemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author yuanhy
* @date 2020-12-13 18:12
*/
@Configuration
public class SecurityConfig {
@Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
实现 UserDetailsService
package com.yuanhy.springsecuritydemo.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
/**
* @author yuanhy
* @date 2020-12-13 18:17
*/
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//根据用户名去数据库查询,不存在则报异常 UsernameNotFoundException,这里测试,固定一个值
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户不存在!");
}
//比较密码,从数据库获取的密码是注册时已经加密过,这里是 123456 ,
String encode = passwordEncoder.encode("123456");
return new User(username,encode, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal"));
}
}
重新启动后,不会出现自动生成密码,然后输入 admin ,123456 就可以访问 //localhost:8080/login.html

自定义登录页面
通过修改配置类,替换Spring Security 自带的登录页面
- 继承
WebSecurityConfigurerAdapter重写protected void configure(HttpSecurity http)方法
package com.yuanhy.springsecuritydemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author yuanhy
* @date 2020-12-13 18:12
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.formLogin()
.loginPage("/login.html");
}
@Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
重启后,访问 //localhost:8080/login.html ,直接访问我们自定义的 login.html ,不再是 Spring Security 内置的,但是,出现一个问题,所有的资源都可以访问,例如 //localhost:8080/success.html 也可以直接访问,需要修改配置类,必须经过登录认证才可以访问,否则返回登录页
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html");
//授权
http.authorizeRequests()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//所有请求都必须经过认证才可以访问,必须登录
.anyRequest().authenticated();
}
完整的配置如下
package com.yuanhy.springsecuritydemo.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
/**
* @author yuanhy
* @date 2020-12-13 18:12
*/
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单 Form 的 action url 对应的接口一致
.loginProcessingUrl("/login")
//登录成功后跳转的 servlet uri
.successForwardUrl("/toSuccess");
//关闭 csrf 防护
http.csrf().disable();
//授权
http.authorizeRequests()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//所有请求都必须经过认证才可以访问,必须登录
.anyRequest().authenticated();
}
@Bean
public PasswordEncoder getPasswordEncoder(){
return new BCryptPasswordEncoder();
}
}
增加登录成功跳转servlet
@RequestMapping("/toSuccess")
public String toSuccess(){
return "redirect:success.html";
}
登录失败后跳转配置,增加 .failureForwardUrl("/toFailure");
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置表单提交
http.formLogin()
//自定义登录页面
.loginPage("/login.html")
//必须和表单 Form 的 action url 对应的接口一致
.loginProcessingUrl("/login")
//登录成功后跳转的 servlet uri
.successForwardUrl("/toSuccess")
.failureForwardUrl("/toFailure");
//关闭 csrf 防护
http.csrf().disable();
//授权
http.authorizeRequests()
//登录失败放行页面
.antMatchers("/failure.html").permitAll()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//所有请求都必须经过认证才可以访问,必须登录
.anyRequest().authenticated();
}
失败 servlet
@RequestMapping("/toFailure")
public String toFailure(){
return "redirect:failure.html";
}
自定义登录用户名和密码
Spring Security 默认 username 、password
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
用户名 : <input type="text" name="username"/><br/>
用户密码 : <input type="password" name="password"/><br/>
<input type="submit"value="登录">
</form>
</body>
</html>
当把 name=”username” 、name=”password” 的 username、password 改变时会登录失败
这里涉及到 UsernamePasswordAuthenticationFilter 过滤器
官方源码 :参数默认 username 、password 、postOnly=true ,表单提交只能是 Post
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
private static final AntPathRequestMatcher DEFAULT_ANT_PATH_REQUEST_MATCHER = new AntPathRequestMatcher("/login", "POST");
private String usernameParameter = "username";
private String passwordParameter = "password";
private boolean postOnly = true;
可以自定义设置表单参数
配置参数
//配置自定义 username、password 参数
.usernameParameter("userName")
.passwordParameter("passWord")
@Override
protected void configure(HttpSecurity http) throws Exception {
//配置表单提交
http.formLogin()
//配置自定义 username、password 参数
.usernameParameter("userName")
.passwordParameter("passWord")
//自定义登录页面
.loginPage("/login.html")
//必须和表单 Form 的 action url 对应的接口一致
.loginProcessingUrl("/login")
//登录成功后跳转的 servlet uri
.successForwardUrl("/toSuccess")
.failureForwardUrl("/toFailure");
//关闭 csrf 防护
http.csrf().disable();
//授权
http.authorizeRequests()
//登录失败放行页面
.antMatchers("/failure.html").permitAll()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//所有请求都必须经过认证才可以访问,必须登录
.anyRequest().authenticated();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>login</title>
</head>
<body>
<form action="/login" method="post">
用户名 : <input type="text" name="userName"/><br/>
用户密码 : <input type="password" name="passWord"/><br/>
<input type="submit"value="登录">
</form>
</body>
</html>
重启后也是可以访问的
自定义跳转到外网页面
以前端控制跳转到百度为例
设置登录成功跳转 :.successForwardUrl("/toSuccess")
进入 successForwardUrl 源码,发现
public FormLoginConfigurer<H> successForwardUrl(String forwardUrl) {
this.successHandler(new ForwardAuthenticationSuccessHandler(forwardUrl));
return this;
}
ForwardAuthenticationSuccessHandler 实现了 AuthenticationSuccessHandler 接口 ,做了一个 forward 转发
public class ForwardAuthenticationSuccessHandler implements AuthenticationSuccessHandler {
private final String forwardUrl;
public ForwardAuthenticationSuccessHandler(String forwardUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> {
return "'" + forwardUrl + "' is not a valid forward URL";
});
this.forwardUrl = forwardUrl;
}
public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
request.getRequestDispatcher(this.forwardUrl).forward(request, response);
}
}
同样,我们也可以自定义一个 SuccessHandler 实现 AuthenticationSuccessHandler 接口,定义 url,添加构造器,重写 onAuthenticationSuccess 方法,调用重定向 :httpServletResponse.sendRedirect(url);
package com.yuanhy.springsecuritydemo.handler;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author yuanhy
* @date 2020-12-14 22:32
*/
public class SuccessHandler implements AuthenticationSuccessHandler {
private String url;
public SuccessHandler(String url) {
this.url =url;
}
@Override
public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException {
//Authentication 认证信息
User user = (User) authentication.getPrincipal();
System.out.println("username : "+user.getUsername());
System.out.println("password : "+user.getPassword());
System.out.println("username : "+user.getAuthorities().toString());
httpServletResponse.sendRedirect(url);
}
}
然后修改配置类 SecurityConfig 中的 .successForwardUrl("/toSuccess") 为以下配置即可
.successHandler(new SuccessHandler("//www.baidu.com"))
自定义登录失败跳转错误页面
登陆失败自定义跳转
设置登录失败跳转 :.failureForwardUrl("/toFailure");
进入 failureForwardUrl 源码,发现
/**
* Forward Authentication Failure Handler
* @param forwardUrl the target URL in case of failure
* @return the {@link FormLoginConfigurer} for additional customization
*/
public FormLoginConfigurer<H> failureForwardUrl(String forwardUrl) {
failureHandler(new ForwardAuthenticationFailureHandler(forwardUrl));
return this;
}
ForwardAuthenticationFailureHandler实现了 AuthenticationFailureHandler 接口 ,做了一个 forward 转发
public class ForwardAuthenticationFailureHandler implements AuthenticationFailureHandler {
private final String forwardUrl;
/**
* @param forwardUrl
*/
public ForwardAuthenticationFailureHandler(String forwardUrl) {
Assert.isTrue(UrlUtils.isValidRedirectUrl(forwardUrl), () -> "'" + forwardUrl + "' is not a valid forward URL");
this.forwardUrl = forwardUrl;
}
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
AuthenticationException exception) throws IOException, ServletException {
request.setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception);
request.getRequestDispatcher(this.forwardUrl).forward(request, response);
}
同样,我们也可以自定义一个 FailureHandler 实现 AuthenticationFailureHandler接口,定义 url,添加构造器,重写 onAuthenticationFailure方法,调用重定向 :response.sendRedirect(url);
package com.yuanhy.springsecuritydemo.handler;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* @author yuanhy
* @date 2020-12-14 22:55
*/
public class FailureHandler implements AuthenticationFailureHandler {
private final String url;
public FailureHandler(String url) {
this.url = url;
}
//AuthenticationException 重点关注异常子类
@Override
public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
response.sendRedirect(url);
}
}
然后修改配置类 SecurityConfig 中的 .failureForwardUrl("/toFailure") 为以下配置即可
//自定义登录失败后跳转的页面
.failureHandler(new FailureHandler("failure.html"));
授权
权限控制
anyRequest().authenticated() 必须放在 antMatchers 后面,按顺序从上往下执行
//授权
http.authorizeRequests()
//登录失败放行页面
.antMatchers("/failure.html").permitAll()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//所有请求都必须经过认证才可以访问,必须登录
.anyRequest().authenticated();
静态资源放行
例如 图片 .jpg 、login.html、.css、.js 等
antMatchers 匹配规则
? 匹配一个字符
* 匹配 0 个或多个字符
** 匹配 0 个或多个目录
/**
* Maps a {@link List} of
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher}
* instances that do not care which {@link HttpMethod} is used.
* @param antPatterns the ant patterns to create
* {@link org.springframework.security.web.util.matcher.AntPathRequestMatcher} from
* @return the object that is chained after creating the {@link RequestMatcher}
*/
public C antMatchers(String... antPatterns) {
Assert.state(!this.anyRequestConfigured, "Can't configure antMatchers after anyRequest");
return chainRequestMatchers(RequestMatchers.antMatchers(antPatterns));
}
在实际项目中经常需要放行静态资源,所以演示放行静态资源文件下的资源
//放行静态资源,放行css、js、images 文件下的所有资源
.antMatchers("/css/**","/js/**","/images/**").permitAll()
把所有的图片放行,但是图片不一定都在 images 文件夹 :.antMatchers("/**/*.jpg").permitAll()
//放行资源 login.html
.antMatchers("/login.html").permitAll()
//放行静态资源,放行 css、js、images 文件下的所有资源
//.antMatchers("/css/**","/js/**","/images/**").permitAll()
//放行后缀为 .jpg 的所有图片
//.antMatchers("/**/*.jpg").permitAll()
//正则表达式匹配
.regexMatchers(".+[.]jpg").permitAll()
配置 ServletPath
spring.mvc.servlet.path=/demo
在 application.properties 配置 spring.mvc.servlet.path=/demo,在配置类中使用 mvcMatchers
.mvcMatchers("/hello").servletPath("/demo").permitAll()
permitAll 允许所有
permitAll、denyAll(禁止所有)、anonymous(匿名)、authenticated(默认登录认证)、fullyAuthenticated(完全认证,用户名和密码认证)、rememberMe(免登录,记住我)
public final class ExpressionUrlAuthorizationConfigurer<H extends HttpSecurityBuilder<H>>
extends AbstractInterceptUrlConfigurer<ExpressionUrlAuthorizationConfigurer<H>, H> {
static final String permitAll = "permitAll";
private static final String denyAll = "denyAll";
private static final String anonymous = "anonymous";
private static final String authenticated = "authenticated";
private static final String fullyAuthenticated = "fullyAuthenticated";
private static final String rememberMe = "rememberMe";
权限控制
删除 ServletPath 配置
增加 main.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<p>权限控制</p>
</body>
</html>
在 login.html 里增加跳转到 main.html 链接
<p style="align-content: center"> 登录成功,请跳转<a href="main.html">权限控制</a></p>
配置权限,如果登录用户不匹配 admin ,则报 403 无权限
http.authorizeRequests()
//权限控制,严格大小写
.antMatchers("/main.html").hasAuthority("admin")
可以配置多权限
.antMatchers("/main.html").hasAnyAuthority("admin","Admin")
角色控制
角色以 ROLE_ 开头匹配
在登录逻辑增加角色
ROLE_root :AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_root")
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println(username);
//根据用户名去数据库查询,不存在则报异常 UsernameNotFoundException,这里测试,固定一个值
if(!"admin".equals(username)){
throw new UsernameNotFoundException("用户不存在!");
}
//比较密码,从数据库获取的密码是注册时已经加密过,这里是 123456 ,
String encode = passwordEncoder.encode("123456");
return new User(username,encode, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_root"));
}
//角色控制,这里不需要 ROLE_ 严格区分大小写
.antMatchers("/main.html").hasRole("root")
//多角色
.antMatchers("/main.html").hasAnyRole("root","temp")
//基于 ip 控制
.antMatchers("/main.html").hasIpAddress("127.0.0.1")
自定义无权限 403 错误提示
创建类 MyAccessDeniedHandler 实现 AccessDeniedHandler,重写 handle 方法
package com.yuanhy.springsecuritydemo.handler;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
/**
* @author yuanhy
* @date 2020-12-15 22:42
*/
@Component
public class MyAccessDeniedHandler implements AccessDeniedHandler {
@Override
public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
response.setHeader("Content-Type","application/json;charset=utf-8");
PrintWriter printWriter = response.getWriter();
printWriter.write("{\"status\":\"error\",\"msg\":\"权限不足,请联系管理员\"}");
printWriter.flush();
printWriter.close();
}
}
在 SecurityConfig 配置
//异常处理
http.exceptionHandling()
.accessDeniedHandler(myAccessDeniedHandler);
自定义 access
创建接口 MyService ,创建实现类 MyServiceImpl
package com.yuanhy.springsecuritydemo.service;
import org.springframework.security.core.Authentication;
import javax.servlet.http.HttpServletRequest;
/**
* @author yuanhy
* @date 2020-12-15 23:26
*/
public interface MyService {
public boolean hasPermission(HttpServletRequest request, Authentication authentication);
}
package com.yuanhy.springsecuritydemo.service;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;
/**
* @author yuanhy
* @date 2020-12-15 23:28
*/
@Service
public class MyServiceImpl implements MyService {
@Override
public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
//获取主体
Object principal = authentication.getPrincipal();
//判断是否属于 UserDetails
if(principal instanceof UserDetails){
UserDetails userDetails = (UserDetails) principal;
Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
return authorities.contains(new SimpleGrantedAuthority(request.getRequestURI()));
}
return false;
}
}
在 SecurityConfig 配置
.anyRequest().access("@myServiceImpl.hasPermission(request,authentication)");
配置 uri /success.html
return new User(username,encode, AuthorityUtils.commaSeparatedStringToAuthorityList("admin,normal,ROLE_root,ROLE_temp,/success.html"));
基于注解的访问控制
默认不可用 ,需要通过在启动类配置 @EnableGlobalMethodSecurity 开启后使用
通常写在 Service 接口或方法上,也可以写在 Controller 或 Controller 的方法上,一般是 Controller,控制接口 URL 是否允许被访问
@Secured
专门用于判断是否具有角色的,能写在方法或类上,参数要以 ROLE_ 开头

