SpringBoot_整合SpringSecurity(前后端分离版)

一:初始化项目

1、创建SpringBoot项目

        <!--spring boot-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

2、整合MyBatis(具体参考我的《Spring Boot整合MyBatis》)

        <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!-- mysql -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>

3、引入SpringSecurity

        <!--spring security 启动器-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!--jwt-->
        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.9.0</version>
        </dependency>

4、创建测试接口http://localhost:8080/hello,进行测试。
当引入security成功之后,在登录测试接口时就会跳转到默认的登录页http://localhost:8080/login。
(默认用户名:user,密码:控制台输出,我这里是28f2036e-c4f2-4097-9a5c-17e7c8a429c4,)
在这里插入图片描述

二:简单原理介绍

1、登录校验流程在这里插入图片描述
2、SpringSecurity简单过滤器链(完整的过滤器大概是14个),前后端分离一般用jwt,前后端不分离一般采用session
在这里插入图片描述

三:认证(UsernamePasswordAuthenticationFiter)

1、登录流程:
在这里插入图片描述
①、登录、自定义登录接口:
调用ProviderManager的方法进行认证,如果认证通过生成jwt和把用户信息存到redis中。

// 认证 实现代码类
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(sysUser.getUserName(), sysUser.getPassword());
Authentication authenticate = authenticationManager.authenticate(authenticationToken);
// 认证通过 生成jwt
LoginUser loginUser = (LoginUser) authenticate.getPrincipal();
String userId = loginUser.getSysUser().getId().toString();
String jwt = JwtUtil.createJWT(userId);// 使用userId生成 jwt
Map<String, String> map = new HashMap<>(1);
map.put("token", jwt);
// 认证通过 存入 redis
redisCache.setCacheObject("login:" + userId, loginUser);


public class SecurityConfig extends WebSecurityConfigurerAdapter {
    //认证 配置代码
    @Override
    protected void configure(HttpSecurity http) throws Exception {
    // ......
	}
}

②、登录、自定义UserDetailsService:
实现到db中查询用户信息,因为原接口是从内存中查询的。

//重写 UserDetailsService 的 loadUserByUsername 方法
public class UserDetailsServiceImpl implements UserDetailsService{
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
		//......
    }
}

//重写UserDetails返回的用户信息
public class LoginUser implements UserDetails {
	//......
}

2、token认证:
在这里插入图片描述
①、校验、定义jwt认证过滤器:
获取toekn、解析token获取其中的userId、从redis中获取用户信息、使用SecurityContextHolder.getContext().setAuthentication()方法存储该对象,这样其他过滤器会通过SecurityContextHolder来获取当前用户信息。

// token认证过滤器
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        // 省略......  拦截到 token不合法等情况 
        // 将 Authentication对象存入 SecurityContextHolder
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        //放行
        filterChain.doFilter(request, response);
    }
}

四:授权(FilterSecurityInterceptor)

1、将用户的权限信息封装到Authentcation当中,存到SecurityContextHolder中。

@Service
public class UserDetailsServiceImpl implements UserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
    	// 省略 ......
    	// 根据用户id查询权限字符串集合
        List<String> list = sysMenuDao.selectPermsByUserId(userInfo.getId());
        return new LoginUser(userInfo, list);
    }
}


public class LoginUser implements UserDetails {
	// ......
	@JSONField(serialize = false) //fastjson注解,表示此属性不会被序列化到redis当中
    private List<SimpleGrantedAuthority> authorities;
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        // 权限为空的时候才往遍历,不为空直接返回
        if (authorities != null) {
            return authorities;
        }
        //把permissions中String类型的权限信息封装成SimpleGrantedAuthority对象
        authorities = new ArrayList<>();
        for (String permission : permissions) {
            SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);
            authorities.add(authority);
        }
        return authorities;
    }
    
    // ......
}


// token过滤器中( JwtAuthenticationTokenFilter )
// 将Authentication对象(用户信息、已认证状态、权限信息)存入 SecurityContextHolder
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);

2、从SecurityContextHolder中获取Authentcation对象,再获取其中的权限信息。

// token过滤器中( JwtAuthenticationTokenFilter )
String redisKey = "login:" + userId;
LoginUser loginUser = redisCache.getCacheObject(redisKey);// 从redis中获取用户信息

3、设置每个资源(方法)所需要的权限(注解形式设置权限)
RBAC(基于角色的权限控制)

//SecurityConfig 配置类开启权限注解功能
@EnableGlobalMethodSecurity(prePostEnabled = true)

/***** 对应资源(方法)上授权 *****/
//常用,该用户在数据库中有 system:dept:list 这个权限标识才能访问
@PreAuthorize("hasAuthority('system:dept:list')")
@PreAuthorize("hasAnyAuthority()")
@PreAuthorize("hasAnyRole()")
@PreAuthorize("hasAnyRole()")
@PreAuthorize("hasPermission()")

五:失败处理(ExceptionTranslationFilter)

public class SecurityConfig extends WebSecurityConfigurerAdapter {
	// ......
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.exceptionHandling() // 配置异常处理器
                .authenticationEntryPoint(authenticationEntryPoint)// 认证失败
                .accessDeniedHandler(accessDeniedHandler); // 授权失败
    }
    // ......
}

1、认证失败处理器

@Component
public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint {
	// ......
}

2、授权失败处理器

@Component
public class AccessDeniedHandlerImpl implements AccessDeniedHandler {
	// ......
}

六:跨域

同时处理 springboot跨域 和 springsecurity跨域

// springboot 跨域配置类
@Configuration
public class 
  • 4
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值