1.引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version><scope>runtime</scope></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.1</version></dependency>2.配置 application.propertiesserver.port=8086
#
spring.application.name=security-sample
spring.main.allow-bean-definition-overriding=true
spring.mvc.static-path-pattern=/static/**
# thymeleaf 配置
spring.thymeleaf.enabled=true
spring.thymeleaf.cache=false
spring.thymeleaf.servlet.content-type=text/html
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.mode=HTML
spring.thymeleaf.prefix=classpath:/templates/
spring.thymeleaf.suffix=.html# 数据库配置
spring.datasource.name=defaultDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/db_plain?autoReconnect=true&useUnicode=true&characterEncoding=utf8&useSSL=false
spring.datasource.username=root
spring.datasource.password=root123
# 连接池配置
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.maximum-pool-size=8
spring.datasource.hikari.minimum-idle=4
spring.datasource.hikari.connection-timeout=30000
spring.datasource.hikari.max-lifetime=50000
spring.datasource.hikari.auto-commit=true
spring.datasource.hikari.pool-name=HikariCP
# mybatis 配置
mybatis.mapper-locations=classpath:mappers/*xml
mybatis.type-aliases-package=com.sky.biz.entity
mybatis.configuration.map-underscore-to-camel-case=true3.定制开发 - 认证流程的 UserDetailsService说明:UserDetailsService 负责在 Security 框架中从数据源中查询出2大主要信息,
分别为:认证信息(账号、密码)、授权信息(角色列表、权限列表)。随后将这些信息封装为 UserDetails 对象返回
留作后续进行登录认证以及权限判断。@Component
public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserService userService;@Autowiredprivate RoleService roleService;@Autowiredprivate PermsService permsService;@Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {BizUser bizUser = userService.queryByUserName(username);// 用户存在,查询封装用户的"角色与权限"信息到 UserDetails中,通常自定义封装对象,继承 UserDetails的子类 Userif(bizUser != null) {// 使用 authorityList 封装角色权限信息List<GrantedAuthority> authorityList = new ArrayList<>();// 查询当前用户 - 角色信息List<Role> roleList = roleService.getRoleListByUserId(bizUser.getId());for (Role role : roleList) {authorityList.add(new SimpleGrantedAuthority("ROLE_" + role.getRoleCode()));}// 查询当前用户 - 权限信息List<Perms> permsList = permsService.getPermsListByUserId(bizUser.getId());for (Perms perm : permsList) {authorityList.add(new SimpleGrantedAuthority(perm.getPermCode()));}return new SecurityUser(bizUser, authorityList);}return null;}}4.定义封装安全信息的实体类:SecurityUserpublic class SecurityUser extends User {private BizUser bizUser;public SecurityUser(BizUser user, Collection<? extends GrantedAuthority> authorities) {super(user.getUserName(), user.getPassword(), true,true, true, true, authorities);this.bizUser = user;}public SecurityUser(String username, String password, Collection<? extends GrantedAuthority> authorities) {super(username, password, authorities);}// get && setpublic BizUser getBizUser() {return bizUser;}public void setBizUser(BizUser bizUser) {this.bizUser = bizUser;}
}5.自定义密码校验的类:PasswordEncoder,这里自由发挥,根据各自公司安全需要自定义主要就是重写 encode(CharSequence rawPassword) 和 matches(CharSequence rawPassword, String encodedPassword) 方法
如果不想自定义就配置成spring-security提供的 BCryptPasswordEncoder 来处理密码加密与校验6.配置Security@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // 开启方法级别的细粒度权限控制
public class SecurityConfig extends WebSecurityConfigurerAdapter {@Autowiredprivate UserDetailsService userDetailsService;// 配置对 HTTP 请求的安全拦截处理@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().antMatchers("/static/**").permitAll().anyRequest().authenticated().and().formLogin().and().csrf().disable().formLogin().loginPage("/login").loginProcessingUrl("/doLogin").defaultSuccessUrl("/main") .failureUrl("/fail") .permitAll();// "/login","/main"与"/fail",都是对应 html页面访问controller跳转路径// 用户权限不够,处理并返回响应http.exceptionHandling().accessDeniedHandler(new AccessDeniedHandler() {@Overridepublic void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {String header = request.getHeader("X-Requested-With");if("XMLHttpRequest".equals(header)) {response.getWriter().print("403"); // 返回ajax 请求对应的 json格式} else {request.getRequestDispatcher("/error403").forward(request, response);}}});}@Beanpublic MyPasswordEncoder passwordEncoder() {return new MyPasswordEncoder();}@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception {auth.userDetailsService(userDetailsService).passwordEncoder(new passwordEncoder());// 或者:auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());}
}7.使用加密时:@Autowiredprivate MyPasswordEncoder passwordEncoder;// 方法1:String encodePwd = passwordEncoder.encode(user.getPassword());// 方法2:String encodePwd = new BCryptPasswordEncoder().encode(user.getPassword());user.setPassword(encodePwd);userMapper.save(user);大体整合完成!