springsecurity实现数据库动态加载资源鉴权规则以及权限表达式

1:在springsecurity的配置文件中添加配制

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().sameOrigin();
        //http.csrf().disable().cors().disable().headers().disable();
        http.authorizeRequests().antMatchers("/", "/index", "/index.html",
                "/toLoginPage").permitAll()

                //.antMatchers("/static/**").permitAll()
//  这个配置就是告诉springsecurity,鉴权规则通过数据库动态加载
.anyRequest().access("@myRbacAuthention.hasPermission(request,authentication)")
                /*.antMatchers("/vip1").hasRole("VIP1")
                .antMatchers("/vip2").hasRole("VIP2")
                .antMatchers("/vip3").hasRole("VIP3")*/;
        // 开启表单认证
        http.formLogin().loginProcessingUrl("/login").loginPage("/toLoginPage")
                // 成功和失败的处理器
                .successHandler(mySavedRequestAwareAuthenticationSuccessHandler)
                .failureHandler(mySimpleUrlAuthenticationFailureHandler);

        // 开启记住我,60秒
        http.rememberMe().rememberMeParameter("rememberMe").tokenValiditySeconds(60);

        // 开启注销
        http.logout().logoutSuccessUrl("/");

        // 处理登出的404错误!springsecurity的csrf(跨站请求伪造)保护
        http.csrf().disable();

        // 一个账户只能一个账号登陆,maxSessionsPreventsLogin(false)设置为false,标识第一个账号登陆后,
        // 同一个账号还可以在其他地方登陆。只是将第一个挤下去,如果设置为true,则同一个账号就不能再次登陆了

        http.sessionManagement().maximumSessions(1).maxSessionsPreventsLogin(false)
                .expiredSessionStrategy(new MySessionInfomantion());
    }

2:自定义一个数据库加载资源鉴权的类

就是加载数据库中查询当前用户所有拥有的权限,然后和当前请求的资源进行比对,成功就返回true,否则就返回false

package com.itgo.springboot.springsecurity.config;

import com.itgo.springboot.springsecurity.mapper.SysUserMapper;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.List;

/**
 * @Description: 自定义的权限表达式
 * @auther: libiao
 * @Email: libiao@163.com
 * @Date: 2020-6-21 14:51
 * @Copyright: (c) 2019-2022  XXXX公司
 */
@Component("myRbacAuthention")
public class MyRbacAuthention {

    private AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Resource
    private SysUserMapper sysUserMapper;
    /**
     * @Description: 判断当前用户是否存在某种权限
     * @author libiao
     * @Date 2020-6-21 14:52
     * @Param
     * @return
     **/
    public boolean hasPermission(HttpServletRequest request, Authentication authentication) {

        Object principal = authentication.getPrincipal();
        if (principal instanceof UserDetails) {
            String username = ((UserDetails) principal).getUsername();
            // 通过用户名查询这个用户的所有权限
            List<String> permissions = sysUserMapper.getAllPermissionByUesrName(username);
            return permissions.stream().anyMatch(
                    url -> antPathMatcher.match(url, request.getRequestURI())
            );
        }
        return false;
    }
}

3:权限表达式

如果需要在方法上做权限表达式,需要配置注解,开启
在springsecurity的配置类中,开启注解
@EnableGlobalMethodSecurity(prePostEnabled = true)// 默认是false

package com.libiao.basicserver.service;

import com.libiao.basicserver.model.Person;
import org.springframework.security.access.prepost.PostAuthorize;
import org.springframework.security.access.prepost.PostFilter;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.access.prepost.PreFilter;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

import static org.springframework.security.core.context.SecurityContextHolder.getContext;

@Service
public class MethodelService {
// 在执行方法之前判断当前用户是否存在admin这个角色
    @PreAuthorize("hasRole('admin')")
    public List<Person> findAll(){
        return null;
    }

// 在执行方法后,判断返回值
    @PostAuthorize("returnObject.name == authentication.name")
    public Person findOne(){
        String authName =
                getContext().getAuthentication().getName();
        System.out.println(authName);
        return new Person("admin");
    }
// 过滤,执行方法之前,过滤掉,不满足要求的参数
    @PreFilter(filterTarget="ids", value="filterObject%2==0")
    public void delete(List<Integer> ids, List<String> usernames) {
        System.out.println();
    }

// 执行方法后,过滤掉不满足要求的返回值
    @PostFilter("filterObject.name == authentication.name")
    public List<Person> findAllPD(){

        List<Person> list = new ArrayList<>();
        list.add(new Person("kobe"));
        list.add(new Person("admin"));

        return list;
    }

}

首先,需要在pom.xml中加入spring security和相关依赖文件: ``` <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-data</artifactId> </dependency> ``` 接着,在application.properties中配置数据库信息: ``` spring.datasource.url=jdbc:mysql://localhost:3306/security?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC spring.datasource.username=root spring.datasource.password=123456 spring.datasource.driver-class-name=com.mysql.jdbc.Driver ``` 然后,创建用户表和权限表,用来存储用户和权限信息。用户表包括用户名和密码,权限表包括权限名称和对应的URL。 接下来,创建UserDetailService实现类,用于从数据库中读取用户信息。代码如下: ``` @Service public class UserDetailsServiceImpl implements UserDetailsService { @Autowired private UserDao userDao; @Override public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException { User user = userDao.findByUserName(userName); if (user == null) { throw new UsernameNotFoundException("用户名不存在"); } List<GrantedAuthority> authorities = new ArrayList<>(); List<Role> roles = user.getRoles(); for (Role role : roles) { authorities.add(new SimpleGrantedAuthority(role.getRoleName())); } return new org.springframework.security.core.userdetails.User(user.getUserName(), user.getPassword(), authorities); } } ``` 然后,创建SecurityConfig类,用于配置Spring Security。代码如下: ``` @Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private UserDetailsServiceImpl userDetailsService; @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/", "/home").permitAll() .antMatchers("/admin/**").hasRole("ADMIN") .anyRequest().authenticated() .and() .formLogin() .loginPage("/login") .permitAll() .and() .logout() .permitAll(); } @Autowired public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } } ``` 其中,configure方法用于配置请求的权限,configureGlobal方法用于设置自定义的UserDetailsService,passwordEncoder方法用于设置密码加密方式。 最后,创建UserController类,用于处理用户登录注册和鉴权请求。代码如下: ``` @RestController public class UserController { @Autowired private UserDao userDao; @Autowired private PasswordEncoder passwordEncoder; @PostMapping("/register") public String register(@RequestParam String userName, @RequestParam String password) { User user = userDao.findByUserName(userName); if (user != null) { return "用户名已存在"; } user = new User(); user.setUserName(userName); user.setPassword(passwordEncoder.encode(password)); userDao.save(user); return "注册成功"; } @PostMapping("/login") public String login(@RequestParam String userName, @RequestParam String password) { try { UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userName, password); Authentication authentication = authenticationManager().authenticate(token); SecurityContextHolder.getContext().setAuthentication(authentication); return "登录成功"; } catch (Exception e) { return "用户名或密码错误"; } } @GetMapping("/admin") @PreAuthorize("hasRole('ADMIN')") public String admin() { return "管理员权限"; } @GetMapping("/user") @PreAuthorize("hasAnyRole('USER','ADMIN')") public String user() { return "用户权限"; } } ``` 其中,register方法用于处理用户注册请求,login方法用于处理用户登录请求,admin和user方法用于处理鉴权请求。 至此,整合spring security实现用户登录注册与鉴权全记录,权限数据库中查询的操作已经完成。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值