关于Spring Security框架

添加Spring Security框架依赖

在这里插入图片描述

        <!-- Spring Security依赖 主要解决认证与授权相关问题 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

Spring Security的配置类

在这里插入图片描述

package cn.tedu.csmallpassport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
}

在这里插入图片描述

package cn.tedu.csmallpassport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // super.configure(http);  // 不要调用父类的同款方法
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

关于登录表单

在这里插入图片描述

package cn.tedu.csmallpassport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // super.configure(http);  // 不要调用父类的同款方法
        // 调用formLogin() 表示启用登录和登出页,如果未调用此方法,则没有登录和登出页
        http.formLogin();
    }
}

关于URL的授权访问

在这里插入图片描述

package cn.tedu.csmallpassport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    // 白名单
    String[] urls = {
            "/login"
    };

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置URL的授权访问
        // 注意: 配置时,各请求的授权访问遵循“第一匹配原则”,即根据代码从上至下,以第1次匹配到的规则为准
        // 所以在配置时,必须将更加精准的配置写在前面,覆盖范围更大的匹配的配置写在后面
        http.authorizeRequests() // 配置URL的授权访问
                .mvcMatchers(urls)  // 匹配某些请求
                .permitAll()  // 直接许可, 即 不需要认证就可以直接访问
                .anyRequest()   // 任何请求
                .authenticated();  // 以上匹配到的请求必须是”已经通过认证的(通过登录的)“


        // super.configure(http);  // 不要调用父类的同款方法
        // 调用formLogin() 表示启用登录和登出页,如果未调用此方法,则没有登录和登出页
        http.formLogin();
    }
}

使用临时的自定义账号实现登录

在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.security;

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;

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        return null;
    }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.security;

import lombok.extern.slf4j.Slf4j;
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.stereotype.Service;

@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        // 假设正确的用户名是root,匹配的密码是1234
        if (!"root".equals(s)) {
            log.warn("用户名【{}】错误,将不会返回有效的UserDetails(用户详情)");
            return null;
        }
        UserDetails userDetails = User.builder()  // 构建者
                .username("root")   // 存入用户名
                .password("1234")   // 存入密码
                .disabled(false)  // 存入启用或禁用的状态
                .accountLocked(false)   // 存入账户是否锁定的状态
                .credentialsExpired(false)   // 存入凭证是否过期的状态
                .accountExpired(false)  // 存入账户是否过期的状态
                .authorities("这是一个临时的山寨权限,暂时没什么用")  // 存入权限列表
                .build();   // 执行构建,得到UserDetails类型的对象
        log.debug("即将向Spring Security返回UserDetails类型的对象,返回结果:{}", userDetails);
        return userDetails;
    }
}

在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.config;

import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.proxy.NoOp;
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.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Slf4j
@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    // 白名单
    String[] urls = {
            "/login"
    };

    @Bean
    public PasswordEncoder passwordEncoder() {
        return NoOpPasswordEncoder.getInstance();
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 配置URL的授权访问
        // 注意: 配置时,各请求的授权访问遵循“第一匹配原则”,即根据代码从上至下,以第1次匹配到的规则为准
        // 所以在配置时,必须将更加精准的配置写在前面,覆盖范围更大的匹配的配置写在后面
        http.authorizeRequests() // 配置URL的授权访问
                .mvcMatchers(urls)  // 匹配某些请求
                .permitAll()  // 直接许可, 即 不需要认证就可以直接访问
                .anyRequest()   // 任何请求
                .authenticated();  // 以上匹配到的请求必须是”已经通过认证的(通过登录的)“

        // super.configure(http);  // 不要调用父类的同款方法
        // 调用formLogin() 表示启用登录和登出页,如果未调用此方法,则没有登录和登出页
        http.formLogin();
    }
}

在这里插入图片描述

使用数据库中的账号实现登录

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.pojo.vo;

import lombok.Data;

import java.io.Serializable;

@Data
public class AdminLoginInfoVO implements Serializable {
    private Long id;
    private String username;
    private String password;
    private Integer enable;
}

在这里插入图片描述

AdminLoginInfoVO getLoginInfoByUsername(String username);

在这里插入图片描述

	<select id="getLoginInfoByUsername" resultMap="LoginInfoResultMap">
        SELECT id, username, password, enable FROM ams_admin WHERE username = #{username}
    </select>
	<resultMap id="LoginInfoResultMap" type="cn.tedu.csmallpassport.pojo.vo.AdminLoginInfoVO">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="enable" property="enable"/>
    </resultMap>

在这里插入图片描述

@Test
    void getLoginInfoByUsername() {
        String username = "root";
        AdminLoginInfoVO loginInfoByUsername = mapper.getLoginInfoByUsername(username);
        System.out.println(loginInfoByUsername);
    }

在这里插入图片描述

package cn.tedu.csmallpassport.security;

import cn.tedu.csmallpassport.mapper.AdminMapper;
import cn.tedu.csmallpassport.pojo.vo.AdminLoginInfoVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
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.stereotype.Service;

@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    AdminMapper adminMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        log.debug("Spring Security自动调用了loadUserByUsername()方法,参数:{}", s);
        AdminLoginInfoVO loginInfo = adminMapper.getLoginInfoByUsername(s);
        log.debug("根据用户名【{}】查询登录信息,结果:{}", s, loginInfo);
        if (loginInfo == null) {
            log.warn("用户名不存在,将无法返回有效的UserDetails对象,则返回null");
            return null;
        }

        log.debug("开始创建返回给Spring Security的UserDetails对象");

        UserDetails userDetails = User.builder()  // 构建者
                .username("root")   // 存入用户名
                .password("1234")   // 存入密码
                .disabled(loginInfo.getEnable() == 0)  // 存入启用或禁用的状态
                .accountLocked(false)   // 存入账户是否锁定的状态
                .credentialsExpired(false)   // 存入凭证是否过期的状态
                .accountExpired(false)  // 存入账户是否过期的状态
                .authorities("这是一个临时的山寨权限,暂时没什么用")  // 存入权限列表
                .build();   // 执行构建,得到UserDetails类型的对象
        log.debug("即将向Spring Security返回UserDetails类型的对象,返回结果:{}", userDetails);
        return userDetails;
    }
}

在这里插入图片描述

 @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

在这里插入图片描述
在这里插入图片描述

http.csrf().disable();

在这里插入图片描述

关于防止伪造的跨域攻击

伪造的跨域攻击:此类攻击是基于“服务器对客户端的浏览器的信任”,例如,用户在浏览器的第1个选项卡中登录了,那么,在第2个、第3个等等同一个浏览器的其它选项卡中访问同样的服务器,也会被视为“已登录”的状态。所以,假设某个用户在浏览器的第1个选项卡中登录了网上银行,此用户在第2个选项卡中打开了另一个网站,此网站可能是恶意的网站(不是此前第1个选项卡的网上银行的网站),在恶意网站中隐藏了一个向网上银行的网站发起请求的链接,并自动发出了请求(比较典型的做法是将链接设置为标签的src属性值,并隐藏此标签使之不显示),则会导致在第2个选项卡中的恶意网站被打开时,就自动的向网上银行发起了请求,而网上银行收到了请求后,会视为“已登录”的状态!

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

以Spring Security默认的登录表单为例:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

前后端分离的登录

在这里插入图片描述

// 白名单
    // 所有路径必须使用 / 作为第1个字符
    // 使用1个星号作为通配符时,表示通配此层级的任意资源,例如:/admins/*,可以匹配 /admins/delete、/admins/add-new
    // 但是,不可以匹配多层级,例如:/admins/* 不可匹配 /admins/9527/delete
    // 使用2个连续的星号,表示通配若干层级的任意资源,例如:/admins/** 可以匹配 /admins/delete、/admins/9527/delete
    String[] urls = {
            "/doc.html",
            "/favicon.ico",
            "/**/*.css",
            "/**/*.js",
            "/swagger-resources",
            "/v2/api-docs",
    };

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@PostMapping("/login")
    public JsonResult login(@RequestBody AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理【管理员登录】的请求,参数:{}", adminLoginDTO);
        // TODO 具体功能待定
        return JsonResult.ok();
    }

在这里插入图片描述

// 白名单
    // 所有路径必须使用 / 作为第1个字符
    // 使用1个星号作为通配符时,表示通配此层级的任意资源,例如:/admins/*,可以匹配 /admins/delete、/admins/add-new
    // 但是,不可以匹配多层级,例如:/admins/* 不可匹配 /admins/9527/delete
    // 使用2个连续的星号,表示通配若干层级的任意资源,例如:/admins/** 可以匹配 /admins/delete、/admins/9527/delete
    String[] urls = {
            "/doc.html",
            "/favicon.ico",
            "/**/*.css",
            "/**/*.js",
            "/swagger-resources",
            "/v2/api-docs",
            "/admins/login"     // 新增
    };

在这里插入图片描述

	@Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

在这里插入图片描述

@Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理【管理员登录】的业务,参数:{}", adminLoginDTO);
        // 创建认证信息
        Authentication authentication = new UsernamePasswordAuthenticationToken(  // 第一个参数当事人, 第二个参数凭证
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword()
        );
        // 执行认证
        authenticationManager.authenticate(authentication);
        // 如果没有出现异常,则表示验证登录成功
        log.debug("验证登录成功");
    }

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

	ERR_UNAUTHORIZED(401, "登录失败"),
    ERR_UNAUTHORIZED_DISABLED(402, "账号被禁用"),

在这里插入图片描述

 	@ExceptionHandler({
            InternalAuthenticationServiceException.class, BadCredentialsException.class
    })
    public JsonResult handleAuthenticationException(AuthenticationException e) {
        log.debug("登录失败,用户名或密码错误!");
        return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED, "登录失败,用户名或密码错误!");
    }

    @ExceptionHandler
    public JsonResult handleDisabledException(DisabledException e) {
        log.debug("登录失败,此账号已经被禁用!");
        return JsonResult.fail(ServiceCode.ERR_UNAUTHORIZED_DISABLED, "登录失败,此账号已经被禁用!");
    }

在这里插入图片描述
在这里插入图片描述

关于通过认证的标准

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

@Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public void login(AdminLoginDTO adminLoginDTO) {
        log.debug("开始处理【管理员登录】的业务,参数:{}", adminLoginDTO);
        // 创建认证信息
        Authentication authentication = new UsernamePasswordAuthenticationToken(  // 第一个参数当事人, 第二个参数凭证
                adminLoginDTO.getUsername(), adminLoginDTO.getPassword()
        );
         
        Authentication authenticationResult = authenticationManager.authenticate(authentication);

        // 如果没有出现异常,则表示验证登录成功,需要将认证信息存入到Security上下文中
        log.debug("验证登录成功,即将向SecurityContext中存入Authentication");
        SecurityContext securityContext = SecurityContextHolder.getContext();
        securityContext.setAuthentication(authenticationResult);
    }

关于authenticate()的返回结果

在这里插入图片描述

2023-04-04 14:45:03.800 DEBUG 6076 --- [nio-9081-exec-1] c.t.c.p.service.impl.AdminServiceImpl    : 验证登录成功,返回的Authentication为:

UsernamePasswordAuthenticationToken [
	Principal=org.springframework.security.core.userdetails.User [
		Username=root, 
		Password=[PROTECTED], 
		Enabled=true, 
		AccountNonExpired=true, 
		credentialsNonExpired=true, 
		AccountNonLocked=true, 
		Granted Authorities=[这是一个临时的山寨权限,暂时没什么用]
	], 
	Credentials=[PROTECTED], 
	Authenticated=true, 
	Details=null, 
	Granted Authorities=[这是一个临时的山寨权限,暂时没什么用]
]

在这里插入图片描述

识别当事人

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.security;

import lombok.Getter;
import lombok.ToString;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

import java.util.Collection;

@ToString(callSuper = true)
public class AdminDetails extends User {
    @Getter
    private Long id;

    public AdminDetails(Long id, String username, String password, boolean enabled, Collection<? extends GrantedAuthority> authorities) {
        super(username, password, enabled, true, true, true, authorities);
        this.id = id;
    }
}

在这里插入图片描述

@Override
public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
    log.debug("Spring Security自动调用了loadUserByUsername()方法,参数:{}", s);

    AdminLoginInfoVO loginInfo = adminMapper.getLoginInfoByUsername(s);
    log.debug("根据用户名【{}】查询登录信息,结果:{}", s, loginInfo);
    if (loginInfo == null) {
        String message = "用户名不存在,将无法返回有效的UserDetails对象,则返回null";
        log.warn(message);
        return null;
    }

    log.debug("开始创建返回给Spring Security的UserDetails对象……");
    
	// ========== 以下是新的代码,替换了原有的代码 ==========
    Collection<GrantedAuthority> authorities = new ArrayList<>();
    authorities.add(new SimpleGrantedAuthority("这是一个临时的山寨权限,暂时没什么用"));

    AdminDetails adminDetails = new AdminDetails(
            loginInfo.getId(),
            loginInfo.getUsername(),
            loginInfo.getPassword(),
            loginInfo.getEnable() == 1,
            authorities
    );

    log.debug("即将向Spring Security返回UserDetails类型的对象,返回结果:{}", adminDetails);
    return adminDetails;
}

在这里插入图片描述
在这里插入图片描述

处理授权

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

select ams_admin.id, ams_admin.username, ams_admin.password, ams_admin.enable, ams_permission.value
from ams_admin
left join ams_admin_role on ams_admin_role.admin_id = ams_admin.id
left join ams_role_permission  on ams_role_permission.role_id = ams_admin_role.role_id
left join ams_permission on ams_permission.id = ams_role_permission.permission_id
where ams_admin.username = 'root'

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

<!-- AdminLoginInfoVO getLoginInfoByUsername(String username); -->
    <select id="getLoginInfoByUsername" resultMap="LoginInfoResultMap">
        SELECT
            <include refid="LoginInfoQueryFields"/>
        FROM ams_admin
        LEFT JOIN ams_admin_role ON ams_admin_role.admin_id = ams_admin.id
        LEFT JOIN ams_role_permission ON ams_role_permission.role_id = ams_admin_role.role_id
        LEFT JOIN ams_permission ON ams_permission.id = ams_role_permission.permission_id
        WHERE username = #{username}
    </select>

    <sql id="LoginInfoQueryFields">
        <if test="true">
            ams_admin.id, 
            ams_admin.username, 
            ams_admin.password, 
            ams_admin.enable,
            ams_permission.value
        </if>
    </sql>

    <!-- collection标签:配置List类型的属性 -->
    <!-- collection标签的property属性:List类型的属性的名称 -->
    <!-- collection标签的ofType属性:List属性的元素的数据类型,取值为元素类型的全限定名,java.lang包下的类可以省略包名 -->
    <!-- collection标签的子级:配置如何创建出List集合中的各个元素对象 -->
    <!-- collection标签的子级的constructor标签:通过构造方法创建对象 -->
    <!-- constructor标签的子级的arg标签:配置构造方法的参数 -->
    <resultMap id="LoginInfoResultMap" type="cn.tedu.csmallpassport.pojo.vo.AdminLoginInfoVO">
        <id column="id" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
        <result column="enable" property="enable"/>
        <collection property="permissions" ofType="java.lang.String">
            <constructor>
                <arg column="value"/>
            </constructor>
        </collection>
    </resultMap>

在这里插入图片描述

2023-04-04 17:20:12.529 DEBUG 12956 --- [           main] c.t.c.passport.mapper.AdminMapperTests   : 

根据用户名【root】查询登录信息完成,查询结果:

AdminLoginInfoVO(
	id=1, 
	username=root, 
	password=$2a$10$N.ZOn9G6/YLFixAOPMg/h.z7pCu6v2XyFDtC4q.jeeGm/TEZyj15C, 
	enable=1, 
	permissions=[
		/ams/admin/read, /ams/admin/add-new, 
		/ams/admin/delete, /ams/admin/update, 
		/pms/product/read, /pms/product/add-new, 
		/pms/product/delete, /pms/product/update, 
		/pms/brand/read, /pms/brand/add-new, 
		/pms/brand/delete, /pms/brand/update, 
		/pms/category/read, /pms/category/add-new, 
		/pms/category/delete, /pms/category/update, 
		/pms/picture/read, /pms/picture/add-new, 
		/pms/picture/delete, /pms/picture/update, 
		/pms/album/read, /pms/album/add-new, 
		/pms/album/delete, /pms/album/update
	]
)

在这里插入图片描述
在这里插入图片描述

package cn.tedu.csmallpassport.security;

import cn.tedu.csmallpassport.mapper.AdminMapper;
import cn.tedu.csmallpassport.pojo.vo.AdminLoginInfoVO;
import lombok.extern.slf4j.Slf4j;
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.stereotype.Service;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;

@Slf4j
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Autowired
    AdminMapper adminMapper;

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        log.debug("Spring Security自动调用了loadUserByUsername()方法,参数:{}", s);

        AdminLoginInfoVO loginInfo = adminMapper.getLoginInfoByUsername(s);
        log.debug("根据用户名【{}】查询登录信息,结果:{}", s, loginInfo);
        if (loginInfo == null) {
            String message = "用户名不存在,将无法返回有效的UserDetails对象,则返回null";
            log.warn(message);
            return null;
        }

        log.debug("开始创建返回给Spring Security的UserDetails对象……");

//        UserDetails userDetails = User.builder()  // 构建者
//                .username(loginInfo.getUsername())   // 存入用户名
//                .password(loginInfo.getPassword())   // 存入密码
//                .disabled(loginInfo.getEnable() == 0)  // 存入启用或禁用的状态
//                .accountLocked(false)   // 存入账户是否锁定的状态
//                .credentialsExpired(false)   // 存入凭证是否过期的状态
//                .accountExpired(false)  // 存入账户是否过期的状态
//                .authorities("这是一个临时的山寨权限,暂时没什么用")  // 存入权限列表
//                .build();   // 执行构建,得到UserDetails类型的对象
//        log.debug("即将向Spring Security返回UserDetails类型的对象,返回结果:{}", userDetails);

        // ========= 以下是本次调整代码 ===========
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        for (String permission : loginInfo.getPermissions()) {
            authorities.add(new SimpleGrantedAuthority(permission));
        }
        // =========== 以上是本次调整代码 ============
        
        AdminDetails adminDetails = new AdminDetails(
                loginInfo.getId(),
                loginInfo.getUsername(),
                loginInfo.getPassword(),
                loginInfo.getEnable() == 1,
                authorities
        );
        return adminDetails;
    }
}

在这里插入图片描述
在这里插入图片描述

@Slf4j
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true) // 新增
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    // 暂不关心方法内部的代码
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

	@ExceptionHandler
    public JsonResult handleAccessDeniedException(AccessDeniedException e) {
        log.debug("禁止访问,当前登录账号无权限访问!");
        return JsonResult.fail(ServiceCode.ERR_FORBIDDEN, "禁止访问,当前登录账号无权限访问!");
    }

配置 jwt 地址: https://editor.csdn.net/md/?articleId=129984203

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值