顾乔芝士网

持续更新的前后端开发技术栈

Spring Security授权RBAC和基于方法的授权

#00后送爸爸的第一台新能源#

package com.alatus.secrurity.config;

import com.alatus.secrurity.entity.User;
import com.alatus.secrurity.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.provisioning.UserDetailsManager;
import org.springframework.stereotype.Component;
import java.util.ArrayList;
import java.util.Collection;

@Component
public class DBUserDetailsManager implements UserDetailsManager, UserDetailsPasswordService {
    @Resource
    private UserMapper userMapper;
    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        return null;
    }

    @Override
    public void createUser(UserDetails userDetails) {
        User userSave = new User();
        userSave.setUsername(userDetails.getUsername());
        userSave.setPassword(userDetails.getPassword());
        userSave.setEnable(true);
        userMapper.insert(userSave);
    }

    @Override
    public void updateUser(UserDetails user) {

    }

    @Override
    public void deleteUser(String username) {

    }

    @Override
    public void changePassword(String oldPassword, String newPassword) {

    }

    @Override
    public boolean userExists(String username) {
        return false;
    }

//    从数据库中获取用户信息
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.selectOne(new QueryWrapper<User>().eq("username", username));
        if(user == null){
            throw new UsernameNotFoundException("用户不存在");
        }
        else{
            Collection<GrantedAuthority> authorities = new ArrayList<>();
            authorities.add(new GrantedAuthority() {
                @Override
                public String getAuthority() {
                    return "USER_ADD";
                }
            });

//            return new org.springframework.security.core.userdetails.User(
//                    user.getUsername(),
//                    user.getPassword(),
//                    user.getEnable(),
//                    true,
//                    true,
//                    true,
//                    authorities
//            );
            return org.springframework.security.core.userdetails.User.withUsername(user.getUsername())
                    .password(user.getPassword())
                    .disabled(!user.getEnable())
                    .credentialsExpired(false)
                    .accountLocked(false)
//                    这两兄弟不能同时存在,会彼此覆盖掉,要么直接限定角色,角色再绑定权限,要么直接给对应用户以权限(这种不太合理)
                    .roles("ADMIN")
                    .authorities("USER_ADD","USER_DELETE")
                    .build();
        }
    }
}
package com.alatus.secrurity.config;

import com.alatus.secrurity.handler.*;
import com.alatus.secrurity.strategy.MySessionInformationExpiredStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import static org.springframework.security.config.Customizer.withDefaults;

@Configuration
//开启Spring Security的自定义配置
@EnableWebSecurity
@EnableMethodSecurity//开启Spring Security的权限控制,基于方法授权
public class WebSecurityConfig {
    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests((authorize) -> {
            authorize
//                    .requestMatchers("/login").permitAll()
//                    .requestMatchers("/logout").permitAll()
//                    .requestMatchers("/user/**").hasRole("ADMIN")
//                    .requestMatchers("/user/list").hasAuthority("USER_LIST")
//                    .requestMatchers("/user/add").hasAuthority("USER_ADD")
                    .anyRequest()//对所有请求开启授权保护
                    .authenticated();//已认证的请求会被自动授权
        });
        http.formLogin(formLogin->{
                    formLogin.loginPage("/login").permitAll()
//                            修改自定义的表单参数
                            .usernameParameter("myUsername")
                            .passwordParameter("myPassword")
                            .failureUrl("/login?failure")
                            .failureHandler(new MyAuthenticationFailureHandler())
//                            这里将默认的登录成功handler改为我们自定义的handler
                            .successHandler(new MyAuthenticationSuccessHandler());
                    //如果不配置permitAll,就会导致出现login页是初始登录页,但是这个页面资源又收到保护,导致跳转回登录页
                    //但是登录页又收到保护,于是又要跳转到登录页,就会形成页面递归导致报错
                });
        http.logout((Logout)->{
            Logout.logoutSuccessHandler(new MyLogoutSuccessHandler());
        });
        http.exceptionHandling(exceptionHandling->{
            exceptionHandling.authenticationEntryPoint(new MyAuthenticationEntryPoint());//请求未认证的处理
            exceptionHandling.accessDeniedHandler(new MyAccessDeniedHandler());
        });
        http.csrf(csrf->csrf.disable());
        http.cors(withDefaults());
        http.sessionManagement(sessionManagement->{
            sessionManagement.maximumSessions(1)//最大几个客户端给用户登录
                    .maxSessionsPreventsLogin(true)
                    .expiredSessionStrategy(new MySessionInformationExpiredStrategy());
        });
        http.cors(withDefaults());
        return http.build();
    }
//    @Bean
//    public UserDetailsService userDetailsService() {
////        创建基于内存的用户信息管理器
////        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
////        创建基于数据库的用户信息管理器
//        DBUserDetailsManager manager = new DBUserDetailsManager();
////        创建UserDetails对象,并设置用户名、密码、角色权限等内容
////        因为用户都在数据库创建保存和查询,所以这里我们使用数据库中的用户信息进行登录验证
////        manager.createUser(User.withDefaultPasswordEncoder().username("admin").password("admin").roles("USER").build());
////        这里我们的manager对象用于管理我们创建的用户信息
//        return manager;
//    }
}
package com.alatus.secrurity.app;

import com.alatus.secrurity.entity.User;
import com.alatus.secrurity.service.UserService;
import com.alibaba.fastjson.JSON;
import jakarta.annotation.Resource;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import java.util.List;

@RestController
@RequestMapping("/user")
public class UserController {
    @Resource
    private UserService userService;
    @GetMapping("/list")
    @PreAuthorize("hasRole('ADMIN') and authentication.name == 'admin'")
    public String userShow(){
        List<User> list = userService.list();
        System.out.println(list.size());
        for (User user : list) {
            System.out.println("User ID: " + user.getId());
            System.out.println("Username: " + user.getUsername());
            System.out.println("Password: " + user.getPassword());
            System.out.println("Enabled: " + user.getEnable());
        }
        for (User user : list) {
            System.out.println(JSON.toJSONString(user));
        }
        return JSON.toJSONString(list);
    }
    @PostMapping("/register")
//    @PreAuthorize("hasRole('USER')")
    @PreAuthorize("hasAuthority('USER_ADD')")
    public String register(@RequestBody User user){
        userService.saveUserDetails(user);
        return "注册成功";
    }
}
package com.alatus.secrurity.handler;

import com.alibaba.fastjson.JSON;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

public class MyLogoutSuccessHandler implements LogoutSuccessHandler {
    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        Map<String, Object> result = new HashMap<>();
        result.put("code", 0);
        result.put("msg", "注销成功");
        result.put("data", authentication.getPrincipal());
        String json = JSON.toJSONString(result);
        response.setContentType("application/json;charset=UTF-8");
        response.getWriter().println(json);
    }
}
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言