SpringBoot集成Security

SpringBoot集成Security,第1张

SpringBoot集成Security

1.授权流程分析

授权一定是在认证通过之后,授权流程是通过FilterSecurityInterceptor拦截器来完成,FilterSecurityInterceptor通过调用SecuritymetadataSource来获取当前访问的资源所需要的权限,然后通过调用AccessDecisionManager投票决定当前用户是否有权限访问当前资源。授权流程如下

用户第一次访问是需要加载用户权限以及用户信息的,再访问成功后,在UserService中会返回当前登录成功的对象到SecurityContextHolder并保存,再用户下一次登录时会优先从SecurityContextHolder查询信息。

1.当客户端向某个资源发起请求,请求到达FilterSecurityInterceptor,然后会调用其父类AbstractSecurityInterceptor
的beforeInvocation方法做授权之前的准备工作

2.在beforeInvocation法中通过SecuritymetadataSource…getAttributes(object);获得资源所需要的访问权限 ,通过SecurityContextHolder.getContext().getAuthentication()获取当前认证用户的认证信息,即包含了认证信息和权限信息的Authentication对象

3.然后FilterSecurityInterceptor通过调用AccessDecisionManager.decide(authenticated, object, attributes);进行授权(authenticated中有用户的权限列表,attributes是资源需要的权限),该方法使用投票器投票来决定用户是否有资源访问权限

AccessDecisionManager接口有三个实现类,他们通过通过AccessDecisionVoter投票器完成投票,三种投票策略如下:
Affirmativebased : 只需有一个投票赞成即可通过
Consensusbased:需要大多数投票赞成即可通过,平票可以配置
Unanimousbased:需要所有的投票赞成才能通过

而投票器也有很多,如RoleVoter通过角色投票,如果ConfigAttribute是以“ROLE_”开头的,则将使用RoleVoter进行投票,AuthenticatedVoter 是用来区分匿名用户、通过Remember-Me认证的用户和完全认证的用户(登录后的)

4.投票通过,请求放行,响应对应的资源给客户端

2.Web授权
2.1.web授权API说明
在Security配置类中,可以通过HttpSecurity.authorizeRequests()给资源指定访问的权限,其API如下:

anyRequest():任何请求
antMatchers(“/path”) :匹配某个资源路径
authenticationed() : 保护URL需要登录访问
permitAll():指定url无需保护(放行)一般用户静态资源
hasRole(String role):某个资源需要用户拥有什么样的role才能访问
hasAuthority(String authority):某个资源需要用户拥有什么样的权限才能访问
hasAnyRole(String …roles):某个资源拥有指定角色中的一个就能访问
hasAnyAuthority(String … authorities):某个资源拥有指定权限中的一个就能访问
access(String attribute):该方法使用SPEL表达式,可以创建复杂的限制
hasIpAddress( String ip):拥有什么样的ip或子网可以访问该资源

web项目授权实战

这里是比较懒了,少创建一张用户角色表,正常创建应该是吧用户表里面的角色id拆分出来,有一张用户和角色关联表
用户表 这里用户密码是通过Security特有的PasswordEncoder加密方式加密,后面会有详细介绍
CREATE TABLE loginuser (
id int(10) NOT NULL AUTO_INCREMENT,
username varchar(255) NOT NULL,
password varchar(255) NOT NULL,
role_id int(10) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
菜单表 菜单表里面存有权限,这个是后面开启注解授权后权限
CREATE TABLE meu (
id int(5) NOT NULL AUTO_INCREMENT,
meuName varchar(255) DEFAULT NULL,
persim varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

角色表
CREATE TABLE role (
id int(10) NOT NULL AUTO_INCREMENT,
roleName varchar(255) DEFAULT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;
角色权限表
CREATE TABLE role_persim (
id int(5) NOT NULL AUTO_INCREMENT,
role_id int(5) NOT NULL,
meu_id int(5) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4;

SecurityConfig

这一个配置类就类似于Handlerinterceptor这一个配置类,起到拦截请求的作用。但在这里面有一个强大的密码解析器PasswordEncoder ,用BCrypt强哈希方法来加密,不可逆,此类每次进行加密的盐值均不相同,也就是说每次相同的明文加密后的密文均不相同,这样就能保证密码尽量小的被测出来。

package com.config;

import com.securityHandler.MyAuthenticationFailureHandler;
import com.securityHandler.MyAuthenticationSuccessHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

@Component
@EnableWebSecurity
//  开启注解授权
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;
    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;
    @Bean
    public PasswordEncoder passwordEncoder()  {//密码密码解析器
        //return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/demo/login").permitAll()//登录请求放行
                .antMatchers("/demo/goIndex").permitAll()//访问登录页面放行
                .antMatchers("/index.html").permitAll() //对登录页面跳转路径放行
                .anyRequest().authenticated() //其他路径都要拦截
                .and().formLogin()
                .passwordParameter("username")
                .passwordParameter("password")//允许表单登录, 设置登陆页,验证登录账号密码
//                .successForwardUrl("/demo/success") // 设置登陆成功后跳转的页面
                .defaultSuccessUrl("/demo/success")  // 默认登录成功访问指定页面,用户未登入,跳转至登入页面,如果登入成功,跳转至用户访问指定页面,用户访问登入页面,默认的跳转页面
                .loginPage("/index.html")   //登录页面跳转地址,如果用户没有登录,会跳转到登录页面
                .loginProcessingUrl("/demo/login")//登录处理地址(必须)和登录表单请求地址一致,对应后用户登录进入认证流程,赋上对应得权限
               
                //推出登录
                .and().logout().permitAll()
                .logoutUrl("/demo/logout")
                .logoutSuccessUrl("/demo/goIndex")//和退出登录请求一致
//                .deletecookies("JSESSIONID")
                //退出登录
                .invalidateHttpSession(true); //登出后session无效;*/

    }
}
UserDetailsService 用户校验以及权限校验
package com.service.impl;

import com.entity.LoginUser;
import com.entity.Meu;
import com.service.ILoginUserService;
import com.service.IMeuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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 java.util.List;
import java.util.stream.Collectors;

@Configuration
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private ILoginUserService loginUserService;
    @Autowired
    private IMeuService meuService;
    
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        LoginUser loginUser = loginUserService.findByUsername(username);
        if (loginUser == null){
            throw new RuntimeException("此用户不存在,请检查输入的账号是否正确");
        }
        //查询该用户权限
        List permission = meuService.selectPermission(loginUser.getId());
        List authorities = permission.stream().map(p -> {
            return new SimpleGrantedAuthority(p.getPersim());
        }).collect(Collectors.toList());
        //将对象用户密码权限信息先放到holder中返回USER对象
        User user1 = new User(username,loginUser.getPassword(),authorities);
        return user1;
    }
}
HTML
//登录页面



    
    登陆


登陆
用户名:

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/4996590.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-11-14
下一篇 2022-11-14

发表评论

登录后才能评论

评论列表(0条)

保存