欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

SpringSecurity

程序员文章站 2024-03-19 13:44:46
...

我的品优购笔记目录里面有相关介绍
SpringBoot集成Security
记住我,实现免密登录
补充:下次会从浏览器读取Cookie中的Toke 给RemberMeService,RemberMeService根据Token到数据库里面去查,如果有记录,就会把Username用户名取出来,取出来之后会调用UserDetailsService,获取用户信息,然后把用户信息放入到SecurityContext里面。

基本流程

AuthenticationManager 的建造器,配置 AuthenticationManagerBuilder 会让Security 自动构建一个 AuthenticationManager(身份认证管理器);如果想要使用该功能你需要配置一个 UserDetailService 和 PasswordEncoder。UserDetailsService 用于在认证器中根据用户传过来的用户名查找一个用户, PasswordEncoder 用于密码的加密与比对,我们存储用户密码的时候用PasswordEncoder.encode() 加密存储,在认证器里会调用 PasswordEncoder.matches() 方法进行密码比对。如果重写了该方法,Security 会启用 DaoAuthenticationProvider 这个认证器,该认证就是先调用 UserDetailsService.loadUserByUsername 然后使用 PasswordEncoder.matches() 进行密码比对,如果认证成功成功则返回一个 Authentication 对象。

原文链接:https://blog.csdn.net/u012702547/article/details/89629415

package com.boot.config;

import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@AllArgsConstructor
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private DetailsService userDetailsService;

    @Autowired
    private DataSource dataSource;
    //自动将token插入persistent_logins表和和从persistent_logins表读取token
    @Bean
    public PersistentTokenRepository persistentTokenRepository() {
        JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
        tokenRepository.setDataSource(dataSource);
        return tokenRepository;
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {

        auth.userDetailsService(userDetailsService).passwordEncoder(new PasswordEncoder() {
            @Override
            public String encode(CharSequence charSequence) {
                return charSequence.toString();
            }

            @Override
            public boolean matches(CharSequence charSequence, String s) {
                return s.equals(charSequence.toString());
            }
        });
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                // 如果有允许匿名的url,填在下面
                .antMatchers("/toregister","/touser/register","/js/**","/image/**").permitAll()
                .anyRequest().authenticated()
                .and()
                // 设置登陆页
                .formLogin().loginPage("/login")
                // 设置登陆成功页
                .successForwardUrl("/").permitAll()
                .failureForwardUrl("/login?error=用户名或密码不正确")
                // 自定义登陆用户名和密码参数,默认为username和password
                // .usernameParameter("username")
                // .passwordParameter("password")
                .and()
                .logout().permitAll()
                //记住我
                .and()
                .rememberMe()
                .tokenRepository(persistentTokenRepository())//设置操作表的Repository
                .tokenValiditySeconds(60 * 60 * 24 * 7)//设置记住我的时间为7天
                .userDetailsService(userDetailsService);//设置userDetailsService

        // 关闭CSRF跨域
        http.csrf().disable();
    }

    @Override
    //静态资源放行
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/images/**","/js/**","/image/**");
    }

}

package com.boot.config;

import com.boot.pojo.SysRole;
import com.boot.pojo.SysUser;
import com.boot.pojo.SysUserRole;
import com.boot.service.SysRoleService;
import com.boot.service.SysUserRoleService;
import com.boot.service.SysUserService;
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.Service;

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

@Service("userDetailsService")
public class DetailsService implements UserDetailsService {
    @Autowired
    private SysUserService userService;

    @Autowired
    private SysRoleService roleService;

    @Autowired
    private SysUserRoleService userRoleService;

    @Override
    public UserDetails loadUserByUsername(String accountNumber) throws UsernameNotFoundException {
        Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        // 从数据库中取出用户信息
        SysUser user = userService.selectByName(accountNumber);
        // 判断用户是否存在
        if(user == null) {
            throw new UsernameNotFoundException("用户名不存在");
        }

        // 添加权限
        List<SysUserRole> userRoles = userRoleService.listByUserId(user.getId());
        for (SysUserRole userRole : userRoles) {
            SysRole role = roleService.selectById(userRole.getRoleId());
            authorities.add(new SimpleGrantedAuthority(role.getName()));
        }

        // 返回UserDetails实现类
        return new User(user.getAccountNumber(), user.getPassword(), authorities);
    }
}

可以在继承WebSecurityConfigurerAdapter的配置类中配置一下属性

  • 允许匿名的Url
  • 登录页,首页,错误页
  • 加用户和权限:withUser(“admin1”) .password("{noop}admin1") .roles(“ADMIN”, “USER”)管理员,同时具有管理员和普通用户权限
  • 记住我
  • 允许放行的静态资源
  • 访问路径所需要的权限: authorizeRequests()
    .antMatchers("/product/").hasRole(“USER”)
    .antMatchers("/admin/
    ").hasRole(“ADMIN”)

Spring Security 核心组件

spring security核心组件有:SecurityContext、SecurityContextHolder、Authentication、Userdetails 和 AuthenticationManager,下面分别介绍。

SecurityContext

安全上下文,用户通过Spring Security 的校验之后,验证信息存储在SecurityContext中,其主要作用就是获取Authentication(身份认证)对象

SecurityContextHolder

SecurityContextHolder看名知义,是一个holder,用来保持住SecurityContext实例的,其作用就是存储当前认证信息。

SecurityContextHolder可以设置指定JVM策略(SecurityContext的存储策略),这个策略有三种:

MODE_THREADLOCAL:SecurityContext 存储在线程中。
MODE_INHERITABLETHREADLOCAL:SecurityContext 存储在线程中,但子线程可以获取到父线程中的 SecurityContext。
MODE_GLOBAL:SecurityContext 在所有线程中都相同。

Authentication

authentication 直译过来是“认证”的意思,在Spring Security 中Authentication用来表示当前用户是谁(认证成功后返回的一个对象),一般来讲你可以理解为authentication就是一组用户名密码信息。Authentication也是一个接口,可以从这个接口中获取这个用户的一些信息

UserDetails

UserDetails,看命知义,是用户信息的意思。其存储的就是用户信息(从数据库查出来的)

UserDetailsService

提到了UserDetails就必须得提到UserDetailsService, UserDetailsService也是一个接口,且只有一个方法loadUserByUsername,他可以用来获取UserDetails。

通常在spring security应用中,我们会自定义一个CustomUserDetailsService来实现UserDetailsService接口,并实现其public UserDetails loadUserByUsername(final String login);方法。我们在实现loadUserByUsername方法的时候,就可以通过查询数据库(或者是缓存、或者是其他的存储形式)来获取用户信息,然后组装成一个UserDetails,(通常是一个org.springframework.security.core.userdetails.User,它继承自UserDetails) 并返回。

在实现loadUserByUsername方法的时候,如果我们通过查库没有查到相关记录,需要抛出一个异常来告诉spring security来“善后”。这个异常是org.springframework.security.core.userdetails.UsernameNotFoundException。

AuthenticationManager

AuthenticationManager 是一个接口
AuthenticationManager 的作用就是校验Authentication,如果验证失败会抛出AuthenticationException异常。AuthenticationException是一个抽象类,因此代码逻辑并不能实例化一个AuthenticationException异常并抛出,实际上抛出的异常通常是其实现类,如DisabledException,LockedException,BadCredentialsException等。BadCredentialsException可能会比较常见,即密码错误的时候。

原文链接:https://www.cnblogs.com/demingblog/p/10874753.html