Spring Security是Spring提供的一套web的应用安全性的完整解决方案。
SpringSecurity采用责任式链的设计模式,它的核心是一组过滤器链。
主要包括:
1,引入maven依赖
- <dependency>
- <groupId>org.springframework.boot</groupId>
- <artifactId>spring-boot-starter-security</artifactId>
- </dependency>
2,启动服务
3,访问 http://localhost:8080/ 会自动跳转进入登录页面 默认用户是 user 密码为服务后端启动显示的安全密码
4,登录成功访问我们提供的接口
5,退出登录 访问 http://localhost:8080/logout
1,引入maven依赖
- <dependency>
- <groupId>org.springframework.bootgroupId>
- <artifactId>spring-boot-starter-securityartifactId>
- dependency>
2,User类
- package com.security.domain;
-
- import com.baomidou.mybatisplus.annotation.IdType;
- import com.baomidou.mybatisplus.annotation.TableId;
- import com.baomidou.mybatisplus.annotation.TableName;
- import io.swagger.annotations.ApiModelProperty;
- import lombok.AllArgsConstructor;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- import java.io.Serializable;
-
- /**
- * @Program: SpringBoot
- * @ClassName User
- * @Author: liutao
- * @Description: 用户类
- * @Create: 2023-06-11 17:22
- * @Version 1.0
- **/
-
- @Data
- @AllArgsConstructor
- @NoArgsConstructor
- @TableName("sys_user")
- public class User implements Serializable {
- private static final long serialVersionUID = 1L;
- @TableId(type = IdType.AUTO)
- @ApiModelProperty("用户id")
- private Integer id;
- @ApiModelProperty("用户名")
- private String username;
- @ApiModelProperty("密码")
- private String password;
- @ApiModelProperty("性别")
- private int sex;
- @ApiModelProperty("年龄")
- private int age;
-
-
- }
3,实现UserDetails接口并重写所有方法
- package com.security.domain;
-
- import com.alibaba.fastjson.annotation.JSONField;
- import lombok.Data;
- import lombok.NoArgsConstructor;
- import org.springframework.security.core.GrantedAuthority;
- import org.springframework.security.core.authority.SimpleGrantedAuthority;
- import org.springframework.security.core.userdetails.UserDetails;
-
- import java.util.Collection;
- import java.util.List;
- import java.util.stream.Collectors;
-
- /**
- * @Program: SpringBoot
- * @ClassName LoginUser
- * @Author: liutao
- * @Description: 登录用户
- * @Create: 2023-06-11 18:17
- * @Version 1.0
- **/
-
- @Data
- @NoArgsConstructor
- public class LoginUser implements UserDetails {
- private User user;
- private List
permissions; - @JSONField(serialize = false)
- private List
authorities; -
- public LoginUser(User user, List
permissions) { - this.user = user;
- this.permissions = permissions;
- }
-
- @Override
- public Collection extends GrantedAuthority> getAuthorities() {
- if (authorities != null) {
- return authorities;
- }
- // authorities = new ArrayList
(); - // // 封装权限信息 -》GrantedAuthority
- // permissions.forEach(s -> {
- // SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(s);
- // authorities.add(simpleGrantedAuthority);
- // });
-
- authorities = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
- return authorities;
- }
-
- @Override
- public String getPassword() {
- return user.getPassword();
- }
-
- @Override
- public String getUsername() {
- return user.getUsername();
- }
-
- @Override
- public boolean isAccountNonExpired() {
- return true;
- }
-
- @Override
- public boolean isAccountNonLocked() {
- return true;
- }
-
- @Override
- public boolean isCredentialsNonExpired() {
- return true;
- }
-
- @Override
- public boolean isEnabled() {
- return true;
- }
- }
4,创建业务接口实现 UserDetailService接口 重写loadUserByUser(String s) 完成业务认证和授权
- package com.security.service.impl;
-
- import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
- import com.security.domain.LoginUser;
- import com.security.domain.Role;
- import com.security.domain.User;
- import com.security.domain.UserRole;
- import com.security.mapper.RoleMapper;
- import com.security.mapper.UserMapper;
- import com.security.mapper.UserRoleMapper;
- import org.springframework.beans.factory.annotation.Autowired;
- 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.Collections;
- import java.util.List;
- import java.util.Objects;
- import java.util.stream.Collectors;
-
- /**
- * @Program: SpringBoot
- * @ClassName service
- * @Author: liutao
- * @Description: 用户业务接口
- * @Create: 2023-06-11 17:43
- * @Version 1.0
- **/
-
- @Service
- public class UserDetailsServiceImpl implements UserDetailsService {
- @Autowired
- private UserMapper mapper;
- @Autowired
- private UserRoleMapper userRoleMapper;
- @Autowired
- private RoleMapper roleMapper;
-
- @Override
- public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
- LambdaQueryWrapper
lambdaQueryWrapper = new LambdaQueryWrapper(); - lambdaQueryWrapper.eq(User::getUsername, s);
- User user = mapper.selectOne(lambdaQueryWrapper);
- if (Objects.isNull(user)) {
- throw new UsernameNotFoundException("用户不存在");
- }
- //TODO 查询对应角色和权限信息 注意角色前一定要以“ROLE_”开头
- // List
auths = new ArrayList(Arrays.asList("ROLE_USER","sys:user")); - List
auths = new ArrayList(Collections.emptyList()); - // 通过用户id获取当前用户所有角色id
- List
ids = userRoleMapper.selectList( - new LambdaQueryWrapper
() - .eq(UserRole::getUserId, user.getId())
- )
- .stream()
- .map(UserRole::getRoleId)
- .collect(Collectors.toList());
- // 获取角色
- List
roles = roleMapper.selectBatchIds(ids) - .stream()
- .map(Role::getFlag)
- .collect(Collectors.toList());
- auths.addAll(roles);
- auths.add("sys:user");
- return new LoginUser(user, auths);
- }
-
-
- }
6,配置核心配置文件
- package com.security.config;
-
- import com.security.filter.JwtAuthenticationTokenFilter;
- import com.security.service.impl.UserDetailsServiceImpl;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.context.annotation.Bean;
- import org.springframework.context.annotation.Configuration;
- import org.springframework.security.authentication.AuthenticationManager;
- 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.configuration.EnableWebSecurity;
- import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.security.crypto.password.PasswordEncoder;
- import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-
- /**
- * @Program: SpringBoot
- * @ClassName SecurityConfig
- * @Author: liutao
- * @Description: security配置类
- * @Create: 2023-06-11 17:39
- * @Version 1.0
- **/
-
- @Configuration
- @EnableGlobalMethodSecurity(jsr250Enabled = true, prePostEnabled = true)
- @EnableWebSecurity
- public class SecurityConfig extends WebSecurityConfigurerAdapter {
- @Autowired
- private UserDetailsServiceImpl userDetailsService;
-
- @Autowired
- private PasswordEncoder passwordEncoder;
-
- @Autowired
- private JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;
-
- @Override
- protected void configure(AuthenticationManagerBuilder auth) throws Exception {
- // 自定义用户认证
- // auth.inMemoryAuthentication().withUser("admin").password("admin").roles("ADMIN");
-
- // 数据库用户认证
- auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder);
- }
-
- /**
- * anyRequest | 匹配所有请求路径
- * access | SpringEl表达式结果为true时可以访问
- * anonymous | 匿名可以访问
- * denyAll | 用户不能访问
- * fullyAuthenticated | 用户完全认证可以访问(非remember-me下自动登录)
- * hasAnyAuthority | 如果有参数,参数表示权限,则其中任何一个权限可以访问
- * hasAnyRole | 如果有参数,参数表示角色,则其中任何一个角色可以访问
- * hasAuthority | 如果有参数,参数表示权限,则其权限可以访问
- * hasIpAddress | 如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
- * hasRole | 如果有参数,参数表示角色,则其角色可以访问
- * permitAll | 用户可以任意访问
- * rememberMe | 允许通过remember-me登录的用户访问
- * authenticated | 用户登录后可访问
- */
- @Override
- protected void configure(HttpSecurity http) throws Exception {
- http
- // CSRF禁用,因为不使用session
- .csrf().disable()
- // 禁用HTTP响应标头
- .headers().cacheControl().disable().and()
- // 过滤请求
- .authorizeRequests()
- // 对于登录toLogin 允许匿名访问
- .mvcMatchers("/toLogin").permitAll().mvcMatchers("/css/**", "/js/**", "/swagger-resources/**", "/webjars/**", "/v2/**", "/doc.html", "/img/**", "/favicon.ico").permitAll()
- // .antMatchers("/**")
- // .hasAnyRole("USER")
- // 除上面外的所有请求全部需要鉴权认证
- .anyRequest().authenticated();
- // .and()
- // .formLogin()
- // .loginProcessingUrl("/toLogin")
- // .successForwardUrl("/home")
- // .and()
- // .httpBasic();
- http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
- }
-
-
- @Bean
- @Override
- protected AuthenticationManager authenticationManager() throws Exception {
- return super.authenticationManager();
- }
-
- @Bean
- public BCryptPasswordEncoder passwordEncoder() {
- return new BCryptPasswordEncoder();
- }
- }
7,抽离web接口代码
- package com.security.service.impl;
-
- import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
- import com.security.common.Result;
- import com.security.domain.LoginUser;
- import com.security.domain.User;
- import com.security.domain.dto.UserDto;
- import com.security.domain.vo.UserVo;
- import com.security.mapper.UserMapper;
- import com.security.service.UserService;
- import com.security.utils.JwtUtil;
- import com.security.utils.RedisUtil;
- import org.slf4j.Logger;
- import org.slf4j.LoggerFactory;
- import org.springframework.beans.BeanUtils;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.authentication.AuthenticationManager;
- import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
- import org.springframework.security.core.Authentication;
- import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
- import org.springframework.stereotype.Service;
-
- import java.util.Objects;
- import java.util.concurrent.TimeUnit;
-
- /**
- * @Program: SpringBoot
- * @ClassName UserServiceImpl
- * @Author: liutao
- * @Description:
- * @Create: 2023-06-12 00:51
- * @Version 1.0
- **/
-
- @Service
- public class UserServiceImpl extends ServiceImpl
implements UserService { - private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);
- @Autowired
- private UserMapper mapper;
-
- @Autowired
- private RedisUtil redisUtil;
-
- @Autowired
- private AuthenticationManager authenticationManager;
- @Autowired
- private BCryptPasswordEncoder passwordEncoder;
-
- @Override
- public UserVo login(UserDto userDto) {
- UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(userDto.getUsername(), userDto.getPassword());
- Authentication authentication = authenticationManager.authenticate(token);
- if (Objects.isNull(authentication)) {
- throw new RuntimeException("登录失败!");
- }
- LoginUser loginUser = (LoginUser) authentication.getPrincipal();
- if (!passwordEncoder.matches(userDto.getPassword(), loginUser.getPassword())) {
- throw new RuntimeException("密码错误");
- }
- UserVo userVo = new UserVo();
- BeanUtils.copyProperties(loginUser.getUser(), userVo);
- String jwtToken = JwtUtil.getToken(userVo.getId().toString());
- String redisKey = "login:" + userVo.getId().toString();
- log.info("当前登录用户:{}",loginUser);
- redisUtil.set(redisKey, loginUser,20L, TimeUnit.MINUTES);
- userVo.setToken(jwtToken);
- return userVo;
- }
- }
8,web接口
- package com.security.controller;
-
- import com.security.common.Result;
- import com.security.domain.dto.UserDto;
- import com.security.domain.vo.UserVo;
- import com.security.service.UserService;
- import org.springframework.beans.factory.annotation.Autowired;
- import org.springframework.security.access.prepost.PreAuthorize;
- import org.springframework.web.bind.annotation.*;
-
- /**
- * @author TAOGE
- */
- @RestController
- public class BasicController {
-
- @Autowired
- private UserService userService;
- @PostMapping("/toLogin")
- public Result
login(@RequestBody UserDto userDto) { - return Result.success("登录成功", userService.login(userDto));
- }
-
- @PreAuthorize("hasRole('ADMIN')")
- @GetMapping("/hasRole")
- public Result
hasRole() { - return Result.success("ADMIN");
- }
-
- @PreAuthorize("hasAuthority('sys:user')")
- @GetMapping("/hasPerm")
- public Result
hasPerm() { - return Result.success("sys:user");
- }
- }
1,启动服务
2,访问 /hasRole接口
3,认证授权
4,携带token访问 /hasRole 和 /hasPerm接口
到这里我们今天的SpringBoot整合和尝鲜SpringSecurity就结束了!!
欢迎双击点赞 666!!!
everybody see you!!!