当前位置:   article > 正文

在rbac项目中集成SpringSecurity_spring security rbac

spring security rbac

在rbac项目中集成SpringSecurity

前提条件

注释:MvcJavaConfig,CheckLoginInterceptor,CheckPermissionInterceptor失效

* 添加依赖
<!--spring security 组件-->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

添加依赖之后发现验证码被拦截了。。。

* 添加SecurityConfig配置
SecurityConfig.java
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private CorsFilter corsFilter;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 不需要认证
                .antMatchers("/api/login","/api/code","/api/logout")
                .permitAll()
                // 所有请求都必须被认证,必须登录后被访问
                .anyRequest()
                .authenticated();
        // 不基于session,关闭csrf
        http.csrf().disable();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

能够完成rbac项目认证功能

* 登录进去(但是没有认证)
* 认证
LoginUser.java
@Data
public class LoginUser implements UserDetails {

    @Getter
    private Employee employee;

    public LoginUser(Employee employee) {
        this.employee = employee;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return null;
    }

    @Override
    public String getPassword() {
        return employee.getPassword();
    }

    @Override
    public String getUsername() {
        return employee.getName();
    }

    /**
     * 账户是否未过期,过期无法验证
     */
    @Override
    public boolean isAccountNonExpired() {
        return true;
    }

    /**
     * 指定用户是否解锁,锁定的用户无法进行身份验证
     */
    @Override
    public boolean isAccountNonLocked() {
        return true;
    }


    /**
     * 账户是否未过期,过期无法验证
     */
    @Override
    public boolean isCredentialsNonExpired() {
        return true;
    }

    /**
     * 是否可用 ,禁用的用户不能身份验证
     */
    @Override
    public boolean isEnabled() {
        return true;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
UserDetailsServiceImpl.java
@Service
public class UserDetailsServiceImpl implements UserDetailsService {

    @Autowired
    private IEmployeeService employeeService;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        Employee employee = employeeService.selectByUserName(username);
        Assert.notNull(employee,"登录用户:"+username + "不存在");
        // 构建UserDetails
        LoginUser loginUser = new LoginUser(employee);
        return loginUser;
    }
}
// 注释:username是接收浏览器的用户名
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
LoginServiceImpl.java
@Service
public class LoginServerImpl implements ILoginServer {

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private PermissionMapper permissionMapper;

    @Autowired
    private EmployeeMapper employeeMapper;


    @Autowired
    private AuthenticationManager authenticationManager;

    @Override
    public Map<String, String> VerificationCode() {
        // 获取验证码
        Map<String, String> verifyCode = VerifyCodeUtil.generateVerifyCode();
        // 存放到Redis中
        String key = Constant.VerifyCode + verifyCode.get("uuid");
        String value = verifyCode.get("code");
        redisUtils.set(key,value,Constant.VERIFY_CODE_EXPIRES);
        // 封装验证码
        verifyCode.remove("code");
        return verifyCode;
    }

    @Override
    public Employee login(LoginInfoVo loginInfoVo) {
        // 1校验参数
        Assert.notNull(loginInfoVo,"非法参数");
        Assert.hasLength(loginInfoVo.getUsername(),"用户名长度不能为空");
        Assert.hasLength(loginInfoVo.getPassword(),"密码长度不能为空");
        // 2校验验证码
            // 用户传过来的验证码
        String userCode = loginInfoVo.getCode();
        String UserUuid = loginInfoVo.getUuid();
        Assert.notNull(userCode,"验证码不能为空");
            // 从Redis中获取验证码code
        String key = Constant.VerifyCode+UserUuid;
        String code = redisUtils.get(key);
            // 校验客户端穿传递过来的验证码
        Assert.state(VerifyCodeUtil.verification(userCode,code,true),"验证码不正确");

//        // 3登录
//        Employee employee = employeeMapper.login(loginInfoVo.getUsername(), loginInfoVo.getPassword());
//        // 4校验登录逻辑
//        Assert.notNull(employee,"用户名或者密码错误");
        // ------springSecurity 认证--------------------------

//        try {
            UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(loginInfoVo.getUsername(), loginInfoVo.getPassword());
            Authentication authenticate = authenticationManager.authenticate(token);
            // 假如认证失败,会抛出异常
            // 正常跑下来,代码认证成功
            // TODO:
            // token.getPrincipal() --- > string:admin
            LoginUser loginUser = (LoginUser)authenticate.getPrincipal(); // loginUser
            Employee employee = loginUser.getEmployee();
//        }catch (Exception e){
//            e.printStackTrace();
//        }

        // ------springSecurity 认证--------------------------

        // 把用户的信息存储到Redis中
            // key 设计 rbac:login_employee:emp_id
            // value 存储的格式 json字符串
        String UserValue = JsonUtils.toJsonString(employee);
        String UserKey= Constant.LOGIN_EMPLOYEE_EMPID + employee.getId();
        redisUtils.set(UserKey,UserValue);

        // 存储当前用户的权限信息到Redis中
        // 通过员工表的id找到查询employee_role 找到 roleId,然后通过roleId去找role_permission到对应的permissionId,
        // 通过permissionId 查询对应permission表找到对应的权限信息
        List<String> selectExpressionByEmpId = permissionMapper.selectExpressionByEmpId(employee.getId());
        String PermissionValue = JsonUtils.toJsonString(selectExpressionByEmpId);
        String PermissionKey = Constant.LOGIN_PERMISSION_EMPID+employee.getId();
        redisUtils.set(PermissionKey,PermissionValue);

        return employee;
    }

    @Override
    public void logout(HttpServletRequest request) {
        // 从请求头中获取empId
        String userId = request.getHeader(Constant.LOGOUT_USER_ID);
        // 参数校验
        Assert.notNull(userId,"非法参数");
        long employeeId = Long.parseLong(userId);

        // 清除Redis中的数据
        redisUtils.del(Constant.LOGIN_PERMISSION_EMPID+employeeId); // 权限
        redisUtils.del(Constant.LOGIN_EMPLOYEE_EMPID+employeeId); // 用户
    }


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
SecurityConfig.java
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private CorsFilter corsFilter;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 不需要认证
                .antMatchers("/api/login","/api/code","/api/logout")
                .permitAll()
                // 所有请求都必须被认证,必须登录后被访问
                .anyRequest()
                .authenticated();

        // 添加跨域过滤器在认证之前

        // 添加JWT filter
        http.addFilterBefore(jwtAuthenticationTokenFilter,
                UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        http.addFilterBefore(corsFilter,JwtAuthenticationTokenFilter.class);

        // 不基于session,关闭csrf
        http.csrf().disable();
    }

    // 身份认证接口
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 写UserDetailsService,告诉SS
        // 并且要告诉密码器
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }

    /**
     * 解决 无法直接注入 AuthenticationManager
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager(); // 直接从父取
    }

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


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60

现象:此时可以登录,但是有跨域问题和每个请求没有认证问题

* 添加跨域过滤器
MvcJavaConfigV2.java
@Configuration
public class MvcJavaConfigV2 implements WebMvcConfigurer {
	// 跨域配置
    @Bean
    public CorsFilter corsFilter(){
        CorsConfiguration configuration = new CorsConfiguration();
        configuration.setAllowCredentials(true);
        // 设置访问源地址
        configuration.addAllowedOrigin("*");
        // 设置访问同源请求头
        configuration.addAllowedHeader("*");
        // 设置访问同源请求方法
        configuration.addAllowedMethod("*");
        // 有效期为1800s
        configuration.setMaxAge(1800L);
        // 添加映射路径,拦截一切请求
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",configuration);
        // 返回新的CorsFilter
        return new CorsFilter(source);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
JwtAuthenticationTokenFilter.java
/**
 * 这个过滤要添加SS中
 * 每个请求都要认证,添加过滤器(JwtAuthenticationTokenFilter.java)
 */
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Autowired
    private RedisUtils redisUtils;
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //
        String userId = request.getHeader(Constant.LOGOUT_USER_ID);
        String employeeJson = redisUtils.get(Constant.LOGIN_EMPLOYEE_EMPID + userId);
        if(!StringUtils.isEmpty(employeeJson)){
            // holder:袋子
            Employee employee=(Employee) JsonUtils.fromJson(employeeJson, Employee.class);
            LoginUser loginUser=new LoginUser(employee);
            // 告诉SS,我认证过了
            UsernamePasswordAuthenticationToken token=
                    new UsernamePasswordAuthenticationToken(loginUser,loginUser.getPassword(),loginUser.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        filterChain.doFilter(request,response);
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
SecurityConfig.java
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private CorsFilter corsFilter;

    @Autowired
    private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 不需要认证
                .antMatchers("/api/login","/api/code","/api/logout")
                .permitAll()
                // 所有请求都必须被认证,必须登录后被访问
                .anyRequest()
                .authenticated();

        // 添加跨域过滤器在认证之前

        // 添加JWT filter(每个请求都要认证,添加过滤器(JwtAuthenticationTokenFilter))
        http.addFilterBefore(jwtAuthenticationTokenFilter,
                UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        http.addFilterBefore(corsFilter,JwtAuthenticationTokenFilter.class);

        // 不基于session,关闭csrf
        http.csrf().disable();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        // 写UserDetailsService,告诉SS
        // 并且要告诉密码器
        auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
        }

    /**
     * 解决 无法直接注入 AuthenticationManager
     * @return
     * @throws Exception
     */
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManager(); // 直接从父取
    }

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


}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59

现象:现在是可以登录,并且可以得到认证…

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/437016
推荐阅读
相关标签
  

闽ICP备14008679号