springboot前后端分离整合spring security

人生之路坎坎坷坷,跌跌撞撞在所难免。但是,不论跌了多少次,你都必须坚强勇敢地站起来。任何时候,无论你面临着生命的何等困惑抑或经受着多少挫折,无论道路多艰难,希望变得如何渺茫,请你不要绝望,再试一次,坚持到底,成功终将属于勇不言败的你。

导读:本篇文章讲解 springboot前后端分离整合spring security,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

基于session

1.导入依赖

<dependencies>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.49</version>
        </dependency>
        <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>
        <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>

2.自定义的用户登录认证逻辑

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;

import java.util.HashSet;
import java.util.Set;

/**
 * 自定义的用户登录认证逻辑
 */
@Component
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Set authoritiesSet = new HashSet();
        // 模拟从数据库中获取用户的角色及权限
        GrantedAuthority authority = new SimpleGrantedAuthority("/v3");
        authoritiesSet.add(authority);
        String encode = passwordEncoder.encode("123456");
        // 模拟对比用户密码
        // 登录成功
        return new User( username, encode, authoritiesSet);
    }

}

3.自定义access权限控制

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 org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.Collection;

/**
 * 自定义access权限控制
 */
@Component("rbacauthorityservice")
public class RbacAuthorityService {

    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {
        Object userInfo = authentication.getPrincipal();
        if (userInfo instanceof UserDetails) {
            UserDetails userDetails = (UserDetails) userInfo;
            Collection<? extends GrantedAuthority> authorities = userDetails.getAuthorities();
            String requestURI = request.getRequestURI();
            // 模拟放行无需权限的接口
            if("/v1".equals(request.getRequestURI())){
                return true;
            }
            // 验证用户是否有包含该权限
            return authorities.contains(new SimpleGrantedAuthority(requestURI));
        }
        return false;
    }

}

4.自定义的安全校验

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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;

@EnableWebSecurity
@Configuration
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;

    /**
     * 设置默认的加密方式(强hash方式加密)
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 去掉 CSRF
        http.csrf().disable()
                .authorizeRequests()//定义哪些URL需要被保护、哪些不需要被保护
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS放行
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/logout").permitAll()
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)"); // RBAC 动态 url 认证
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);//匿名用户访问无权限资源时的异常处理
    }

}


import java.io.Serializable;

/**
 * @author zhoumin
 * @version 1.0
 * @description API层统一参数回调
 * @date 2021/6/17 15:17
 */
public class ApiResult<T> implements Serializable {

    private static final long serialVersionUID = -4038477637423906177L;

    /**
     * 响应体
     */
    private T data;

    /**
     * 是否成功
     */
    private boolean isSuccess;

    /**
     * 请求返回的消息
     */
    private String msg;

    /**
     * 错误码
     */
    private String errorCode;

    /**
     * 请求成功回调
     */
    public static ApiResult successMsg() {
        return new ApiResult()
                .setErrorCode("200")
                .setSuccess(true)
                .setMsg("ok");
    }

    /**
     * 请求成功回调
     *
     * @param Object 对象
     */
    public static ApiResult successMsg(Object Object) {
        return new ApiResult()
                .setErrorCode("200")
                .setSuccess(true)
                .setMsg("ok")
                .setData(Object);
    }

    /**
     * 请求失败回调
     *
     * @param code 状态码
     * @param msg  描述信息
     */
    public static ApiResult errorMsg(String code, String msg) {
        return new ApiResult()
                .setErrorCode(code)
                .setMsg(msg)
                .setSuccess(false);
    }

    /**
     * 请求失败回调
     *
     * @param msg 描述信息
     */
    public static ApiResult errorMsg(String msg) {
        return new ApiResult()
                .setErrorCode("500")
                .setMsg(msg)
                .setSuccess(false);
    }

    /**
     * 请求失败回调
     *  @param errorCode 错误枚举
     */
    public static ApiResult errorMsg(ErrorCode errorCode) {
        return new ApiResult()
                .setErrorCode(errorCode.getErrorCode())
                .setMsg(errorCode.getErrorMsg())
                .setSuccess(false);
    }


    public T getData() {
        return data;
    }

    public String getErrorCode() {
        return errorCode;
    }

    public String getMsg() {
        return msg;
    }

    public ApiResult<T> setData(T data) {
        this.data = data;
        return this;
    }

    public boolean isSuccess() {
        return isSuccess;
    }

    public ApiResult<T> setSuccess(boolean success) {
        isSuccess = success;
        return this;
    }

    public ApiResult<T> setErrorCode(String errorCode) {
        this.errorCode = errorCode;
        return this;
    }

    public ApiResult<T> setMsg(String msg) {
        this.msg = msg;
        return this;
    }

}

import com.alibaba.fastjson.JSON;

import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;


/**
 * @author zhoumin
 * @version 1.0
 * @description 用户权限不足时反给前端的数据
 * @date 2021/6/21 10:32
 */
@Component
public class AjaxAccessDeniedHandler implements AccessDeniedHandler {

    @Override
    public void handle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AccessDeniedException e) throws IOException {
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setHeader("Content-Type", "application/json");
        httpServletResponse.getWriter().write(JSON.toJSONString(ApiResult.errorMsg("用户权限不足")));
    }

}
import com.alibaba.fastjson.JSON;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @author zhoumin
 * @version 1.0
 * @description 用户没登陆时反给前端的数据
 * @date 2021/6/21 10:33
 */
@Component
public class AjaxAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException {
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.setHeader("Content-Type", "application/json");
        httpServletResponse.getWriter().write(JSON.toJSONString(ApiResult.errorMsg("用户未登录")));
    }
}

5.测试类

import com.zm.config.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class TestController {

    @Autowired
    MyUserDetailsService myUserDetailsService;

    @GetMapping("v1")
    public String v1() {
        return "v1 hello world";
    }

    @GetMapping("v2")
    public String v2() {
        return "v2 hello world";
    }

    @GetMapping("v3")
    public String v3() {
        return "v3 hello world";
    }

    @PostMapping("/login")
    public String login() {
        UserDetails userDetails = myUserDetailsService.loadUserByUsername("zhou");
        SecurityContextHolder.getContext()
                .setAuthentication(
                        new UsernamePasswordAuthenticationToken(userDetails,
                                userDetails.getPassword(), userDetails.getAuthorities()));
        return "login ok";
    }

    @GetMapping("/logout")
    public void logout() {
        SecurityContextHolder.clearContext();
    }

}

6.测试结果

未登录进行提示
在这里插入图片描述
登录成功后可以进行访问
在这里插入图片描述
在这里插入图片描述

基于spring session集群 分布式中的使用

链接: springboot-整合spring-session-redis在nginx下实现session共享(九).

补充链接: Springboot http session支持分布式;同时支持 cookie 和 header 传递;websocket 连接 共享 http session.

/**
 * 分布式session-redis配置
 */
// session托管到redis
// maxInactiveIntervalInSeconds单位:秒;
// RedisFlushMode有两个参数:ON_SAVE(表示在response commit前刷新缓存),IMMEDIATE(表示只要有更新,就刷新缓存)
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.data.redis.config.ConfigureRedisAction;
import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession;
import org.springframework.session.web.http.HeaderHttpSessionIdResolver;

@EnableRedisHttpSession(redisNamespace = "session")
@Configuration
public class RedisHttpSessionConfig {

    //这里有个小坑,如果服务器用的是云服务器,不加这个会报错
    @Bean
    public static ConfigureRedisAction configureRedisAction() {
        return ConfigureRedisAction.NO_OP;
    }

    //可自定义session策略,这里配置的是Header方式(有提供Header,Cookie等方式)
    @Bean
    public HeaderHttpSessionIdResolver httpSessionStrategy() {
        // 设置HttpServletRequest中Header里的自定义token名称
        return new HeaderHttpSessionIdResolver("token");
    }

}

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@EnableWebSecurity
@Configuration
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;

    /**
     * 设置默认的加密方式(强hash方式加密)
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 去掉 CSRF
        http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and().authorizeRequests()//定义哪些URL需要被保护、哪些不需要被保护
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS放行
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/logout").permitAll()
                .antMatchers(HttpMethod.GET, "/get/**").permitAll()// /get/xxx放行
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)"); // RBAC 动态 url 认证
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);//匿名用户访问无权限资源时的异常处理
    }

}

基于JWT

分布式项目中的使用

springboot和springsecurity整合OAuth2
Spring Cloud Security OAuth2 实现分布式系统授权
链接: 深入理解Spring Cloud Security OAuth2及JWT.

解决与springboot admin的安全认证

解决方案:配置多个WebSecurityConfigurerAdapterOrder() 顺序加载

链接: 整合springboot admin 监控 – springboot(十五).

链接: 多个 WebSecurityConfigurerAdapter 的 order 问题.


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Order(3)
@EnableWebSecurity
@Configuration
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;

    /**
     * 设置默认的加密方式(强hash方式加密)
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 去掉 CSRF
        http.csrf().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and().authorizeRequests()//定义哪些URL需要被保护、哪些不需要被保护
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS放行
                .antMatchers("/actuator/**").permitAll() // actuator监控接口放行,不指定请求方式

                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/logout").permitAll()
                .antMatchers(HttpMethod.GET, "/get/**").permitAll()
                .anyRequest()
                .access("@rbacauthorityservice.hasPermission(request,authentication)"); // RBAC 动态 url 认证
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);//匿名用户访问无权限资源时的异常处理
    }

}

import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
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.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;

@Order(4)
@Configuration
public class SecuritySecureConfig extends WebSecurityConfigurerAdapter {

    /***
     * 指定让它拦截actuator的接口即可,业务相关的接口由业务权限系统去控制
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic().and().authorizeRequests().antMatchers("/actuator/**").authenticated().anyRequest().permitAll();
        // 关闭CSRF,否则POST请求必须带上token
        http.csrf().disable();
    }

    /**
     * 在内存中配置一个用户,admin/admin分别是用户名和密码,这个用户拥有USER角色。
     * withDefaultPasswordEncoder 被遗弃,原因是不安全,只能在例子中使用
     *
     * @param auth
     * @throws Exception
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        auth.inMemoryAuthentication()
                .withUser("user")
                .password(encoder.encode("user"))
                .roles("USER");
    }
}


参考链接

链接: spring-session(一)揭秘.

链接: Springboot + Spring Security 实现前后端分离登录认证及权限控制.

链接: springboot+springsecurity+mybatis+JWT+Redis 实现前后端离(实战篇).

链接: SpringBoot Security前后端分离登录验证.

链接: SpringBoot+SpringSecurity+jwt实现前后端分离的权限认证(不用security的登陆和注销).

链接: 基于 spring-session 解决分布式 session 共享问题.


User(String username, String password, boolean enabled, boolean accountNonExpired, boolean credentialsNonExpired, boolean accountNonLocked, Collection<? extends GrantedAuthority> authorities)

其中参数:
String username:用户名
String password: 密码
boolean enabled: 账号是否可用
boolean accountNonExpired:账号是否过期
boolean credentialsNonExpired:密码是否过期
boolean accountNonLocked:账号是否锁定
Collection<? extends GrantedAuthority> authorities):用户权限列表

基于固定角色的权限认证

package com.example.course.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
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;


@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
@Configuration
public class MyWebSecurityConfigurer extends WebSecurityConfigurerAdapter {

    @Autowired
    AjaxAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    AjaxAccessDeniedHandler accessDeniedHandler;

    /**
     * 设置默认的加密方式(强hash方式加密)
     */
    @Bean
    public BCryptPasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 去掉 CSRF
        http.csrf().disable()
                .authorizeRequests()// 开启权限控制,通过ANT规范,自定义逻辑
                .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // OPTIONS放行
                .antMatchers(HttpMethod.POST, "/login").permitAll()
                .antMatchers(HttpMethod.GET, "/logout").permitAll()
                // 可以用请求url前准 基于角色的权限控制
//                .antMatchers("/admin/**").hasRole("GLY")
//                .antMatchers("/xs/**").hasRole("XS")
                .anyRequest()//任意请求
                .authenticated();//必须经过认证 只要登陆就能访问

  ; 
        http.exceptionHandling().accessDeniedHandler(accessDeniedHandler); // 无权访问 JSON 格式的数据
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint);//匿名用户访问无权限资源时的异常处理
    }

}
package com.example.course.test;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;

import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;

/**
 * @Author:lzf
 * @Date: 2022/1/25
 */
@Component
public class MyUserDetailsService implements UserDetailsService {

    @Resource
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Set authoritiesSet = new HashSet();
        // 模拟从数据库中获取用户的角色及权限
        GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_XS");
        authoritiesSet.add(authority);
        String encode = passwordEncoder.encode("123456");
        // 模拟对比用户密码
        // 登录成功
        return new User( username, encode, authoritiesSet);
    }

}
package com.example.course.test;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;

/**
 * @Author:lzf
 * @Date: 2022/1/25
 */
@RestController
public class TestController {

    @Autowired
    MyUserDetailsService myUserDetailsService;

    @PreAuthorize("hasRole('ROLE_XS')")
    @GetMapping("/xs/v1")
    public String v1() {
        return "v1 hello world";
    }

    @PreAuthorize("hasRole('ROLE_LS')")
    @GetMapping("v2")
    public String v2() {
        return "v2 hello world";
    }

    @PreAuthorize("hasRole('ROLE_GLY')")
    @GetMapping("/admin/v3")
    public String v3() {
        return "v3 hello world";
    }

    @PostMapping("/login")
    public String login() {
        UserDetails userDetails = myUserDetailsService.loadUserByUsername("zhou");
        SecurityContextHolder.getContext()
                .setAuthentication(
                        new UsernamePasswordAuthenticationToken(userDetails,
                                userDetails.getPassword(), userDetails.getAuthorities()));
        return "login ok";
    }

    @GetMapping("/logout")
    public void logout() {
        SecurityContextHolder.clearContext();
    }

}

注意

在UserDetailsService使用loadUserByUsername构建当前登录用户时,可以选择两种授权方法,即角色授权和权限授权,对应使用的代码是hasRole和hasAuthority,而这两种方式在设置时也有不同,下面介绍一下:

角色授权:授权代码需要加ROLE_前缀,controller上使用时不要加前缀
权限授权:设置和使用时,名称保持一至即可

security 鉴权方式常用的有两种配置,

1、配置文件中配置;
2、使用注解标注;
他们都是基于 acess 表达式,如果需要自定义逻辑的鉴权认证,只需要自定义 access 表达式即可。

注解默认不可用,通过开启注解:在配置类中开启注解

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)

@Secured:专门判断用户是否具有角色,可以写在方法或类上,参数以 ROLE_ 开头
@PreAuthorize\PostAuthorize: PreAuthorize 访问的类或方法执行前判断权限,而 PostAuthorize 在执行之后,Post 基本不用;允许与 ROLE_ 开头。

@Component
public class MyUserDetailService implements UserDetailsService {
  @Autowired
  private PasswordEncoder passwordEncoder;

  @Override
  public UserDetails loadUserByUsername(String name) throws UsernameNotFoundException {
    User user = new User(name,
        passwordEncoder.encode("123456"),
        AuthorityUtils.commaSeparatedStringToAuthorityList("read,ROLE_USER"));//设置权限和角色
    // 1. commaSeparatedStringToAuthorityList放入角色时需要加前缀ROLE_,而在controller使用时不需要加ROLE_前缀
    // 2. 放入的是权限时,不能加ROLE_前缀,hasAuthority与放入的权限名称对应即可
    return user;
  }
}

//读权限
@GetMapping("/read")
@PreAuthorize("hasAuthority('read')")
public String readDate() {
    return "have a read authority";
}

//读写权限
@GetMapping("/read-or-write")
@PreAuthorize("hasAnyAuthority('read','write')")
public String readWriteDate() {
    return "have a read or write authority";
}

//admin角色
@GetMapping("/admin-role")
@PreAuthorize("hasRole('admin')")
public String readAdmin() {
    return "have a admin role";
}

链接: SpringSecurity设置角色和权限.
链接: springboot security 权限控制 – @PreAuthorize 的使用.

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/133933.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!