单体架构SpringSecurity认证中心

一:什么是认证授权

  认证是对身份的确认,授权是对权限的控制,所有的认证授权都是基于RBAC基于角色的权限控制模型,权限与角色关联,用户与角色关联

二:什么是SpringSecurity

  SpringSecurity是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架,减少了为企业系统安全控制编写的大量重复代码

三:Security认证入门

 3.1引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

 3.2编写认证成功后的跳转器

@Controller
public class AuthController {
	//登录成功后重定向地址
    @RequestMapping("/loginSuccess")
    @ResponseBody
    public String loginSuccess(){
        return "登录成功";
	} 
}

 3.3配置SpringSecurity

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

     //提供用户信息,这里没有从数据库查询用户信息,在内存中模拟
    @Bean
    public UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager inMemoryUserDetailsManager = 
        new InMemoryUserDetailsManager();
        inMemoryUserDetailsManager.createUser(User.withUsername("zs").password("123").authorities("admin").build());
        return inMemoryUserDetailsManager;
    }
  

    //密码编码器:不加密
    @Bean
    public PasswordEncoder passwordEncoder(){
        return NoOpPasswordEncoder.getInstance();
    }
    
    //授权规则配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()                                //授权配置
                .antMatchers("/login").permitAll()  //登录路径放行
                .anyRequest().authenticated()                   //其他路径都要认证之后才能访问
                .and().formLogin()                              //允许表单登录
                .successForwardUrl("/loginSuccess")             // 设置登陆成功页
                .and().logout().permitAll()                    //登出路径放行 /logout
                .and().csrf().disable();                        //关闭跨域伪造检查
    }
}

 3.4直接访问服务端口号+login,输入用户名zs,密码123即可登录成功,返回登录成功后的跳转器的内容

 3.5上面是将用户信息写死在内存中进行模拟的,我们可以直接向数据库查询

 3.5.1注释掉配置类中的用户信息方法,自定义一个类去实现UserDetailsService接口,重写loadUserByUsername方法,在这个方法中向数据库中进行查询,需要返回一个User对象,传入用户名、密码、权限集合即可

package cn.ybl.config;

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.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

     //提供用户信息,这里没有从数据库查询用户信息,在内存中模拟
//    @Bean
//    public UserDetailsService userDetailsService(){
//        InMemoryUserDetailsManager inMemoryUserDetailsManager =
//        new InMemoryUserDetailsManager();
//        inMemoryUserDetailsManager.createUser(User.withUsername("zs").password("123").authorities("admin").build());
//        return inMemoryUserDetailsManager;
//    }

    //测试
    public static void main(String[] args) {
        BCryptPasswordEncoder encryption = new BCryptPasswordEncoder();
        //加密,每次加密得到的结果不一样,但是底层会自动进行对比,不影响
        String encode = encryption.encode("123");
        String encode1 = encryption.encode("123");
        System.out.println(encode1);
        System.out.println(encode);
        //对比密码和密码加密字符串
        boolean matches = encryption.matches("123", "$2a$10$SLdM4KRwriqmYqEQZbDJveEjHu0EBOcrYPib893E/vtAARczJ2h0W");
        System.out.println(matches);
    }

    //指定密码编码器进行加密密码:BCryptPasswordEncoder
    @Bean
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }
    
    //授权规则配置
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()                                //授权配置
                .antMatchers("/login").permitAll()  //登录路径放行
                .anyRequest().authenticated()                   //其他路径都要认证之后才能访问
                .and().formLogin()                              //允许表单登录
                .successForwardUrl("/loginSuccess")             // 设置登陆成功页
                .and().logout().permitAll()                    //登出路径放行 /logout
                .and().csrf().disable();                        //关闭跨域伪造检查
    }
}
package cn.ybl.userDetail;

import cn.ybl.domain.Login;
import cn.ybl.domain.LoginLog;
import cn.ybl.domain.Permission;
import cn.ybl.enums.GlobalErrorCode;
import cn.ybl.service.ILoginLogService;
import cn.ybl.service.ILoginService;
import cn.ybl.service.IPermissionService;
import cn.ybl.util.AssertUtil;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
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.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author Mr.Yang
 * @Date 2022/9/23 11:54
 * @description
 */
@Component
public class MyUserDetailServiceImpl implements UserDetailsService {

    @Autowired
    private ILoginService loginService;

    @Autowired
    private IPermissionService permissionService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Wrapper<Login> wrapper = new EntityWrapper<>();
        wrapper.eq("username",username);
        Login login = loginService.selectOne(wrapper);
        //登录用户不存在
        AssertUtil.isNotNull(login, GlobalErrorCode.LOGIN_USER_EMPTY);
        //查询当前登录用户的权限
        List<Permission> permissions = permissionService.loadAuthority(login.getId());
        //将对象转为权限字段的集合
        List<GrantedAuthority> authorities = permissions.stream().map(p -> new SimpleGrantedAuthority(p.getSn())).collect(Collectors.toList());
        return new User(
                login.getUsername(),
                login.getPassword(),
                authorities);
    }
}

四:Security授权入门

4.1web授权

//动态添加授权:从数据库动态查询出,哪些资源需要什么样的权限
List<Permission> permissions = loginMapper.listPermissions();
for(Permission permission : permissions){
    //如: /employee/list    需要     employee:list 权限才能访问
    http.authorizeRequests().antMatchers(permission.getResource()).hasAuthority(permission.getSn());
}

4.2方法授权

在配置类上开启注解:

@EnableGlobalMethodSecurity(securedEnabled = true,prePostEnabled= true)

在受限的接口上打上注解:

@PreAuthorize("hasAnyAuthority('employee:add','employee:update')")
@RequestMapping("/employee/add")   //要访问employee/add就必须有employee:add或者employee:update其中一个权限
public String add(){
	return "employee.add";
}

 

posted @ 2022-09-23 14:05  yyybl  阅读(41)  评论(0)    收藏  举报