SpringSecurity
我的品优购笔记目录里面有相关介绍
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