栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Spring Security&前后端分离项目的使用

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Spring Security&前后端分离项目的使用

整体思路
  1. 前端页面登录,绑定对象,发送axious到后端,进行验证
  2. 后端接收到前端的信息,此时密码为明文,而数据库中密码为密文,只能通过用户名查询数据库,判断用户是否存在,如果存在,通过BCryptPasswordEncoder对密码进行验证
  3. 验证密码通过后,查询用户的角色和权限信息,放到用户对象中,此时只需要字符串即可
  4. 通过私钥进行加密,颁发令牌到前端
  5. 前端接收到登录后的响应,判断是否成功登录,如果成功将token存在localstorage中,然后通过路由跳转页面到首页,登录操作完毕
  6. 此时访问其他资源会报403,因为springsecurity的上下文中并没有用户信息,用户角色和用户的权限,这个工作由springsecurity的FilterSecurityInterceptor这个过滤器来执行,我们需要在basicAuthenticationFilter这个过滤器生效时重写,验证token并将token中的用户信息放到springsecurity的上下文中
  7. 重写basicAuthenticationFilter时注意,此过滤器在FilterSecurityInterceptor之前,先要放行登录和验证请求,必须要return,使用SecurityContextHolder获取context上下文设置认证信息,这个认证信息需要UsernamepasswordAuthenticationToken对象利用构造方法创建,形参token中的载荷,null,authorities,其中的authorities通过AuthoritUtils中的commaSeparatedStringtoAuthorityList获取
  8. 前端发送请求时就需要将正确的token放到请求头中,后端验证之后方可访问资源,在vue的utils下的request.js中请求前从localstorage中获取token,然后设置到请求头中
  9. 此时如若token不正确或过期,无法访问资源,但依然会停留在访问页面,这样的用户体验不好,所以需要增加一个认证环节
  10. 后台认证:同样利用公钥解析请求头中的token,此过程无异常则表示token合法,正常返回一个ResultVO,需要注意的是:该认证的请求也需要在basicAuthenticationFilter和security配置类中放行
  11. 前端认证:在main.js中解开之前注释的permission组件,在permission.js中发送后台认证的请求,通过返回的数据判断token是否有效,有效则让原请求去访问资源,需要注意的是:要判断该请求是否是登录请求,若是登录请求可直接放行,访问登录页面,若token不合法就跳回登录页面
1. 登录认证,颁发令牌
  • 直接使用vue的index.vue界面,改变其中username和password的绑定

        
          
        
        
      

      
        
          
        
        
  • 修改api,发送axious后端登录验证
import request from '@/utils/request'

export function login(data) {
  return request({
    url: '/user/login',
    method: 'post',
    data
  })
}
  • 后端controller层
@PostMapping("login")
    @ApiOperation("用户登录")
    public ResultVO login(@RequestBody SysUser sysUser) {
        return userService.login(sysUser);
    }
  • 后端service层
@Override
    public ResultVO login(SysUser loginUser) {
        try {
            if (loginUser == null) {
                return new ResultVO(false, "用户名或密码不正确");
            }
            // 通过用户名查询用户是否存在,因为密码再数据库中是密文
            SysUser userInDB = userMapper.findUserByUserName(loginUser.getUserName());
            if (userInDB == null) {
                // 用户不存在
                return new ResultVO(false, "用户名或密码不正确");
            }
            // 用户存在,对比密码
            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
            // 前一个参数是明文密码,后一个是数据库中的密文密码
            boolean matches = encoder.matches(loginUser.getPassword(), userInDB.getPassword());

            if (!matches) {
                // 密码不匹配
                return new ResultVO(false, "用户名或密码不正确");
            }
            // 密码匹配,颁发令牌
            // 1.获取用户的角色信息
            List rolesList = userMapper.findRolesByUserId(String.valueOf(userInDB.getUserId()));
            String roles = "";
            // 遍历集合
            for (String roleName : rolesList) {
                roles += roleName + ",";
            }
            roles = roles.substring(0, roles.length() - 1);
            // 设置用户的角色信息
            userInDB.setRoles(roles);
            // 2.获取用户的权限信息
            List permissionList = userMapper.findPermissionByUserId(userInDB.getUserId());
            String permissions = "";
            // 遍历集合
            for (String permissionName : permissionList) {
                permissions += permissionName + ",";
            }
            permissions = permissions.substring(0, permissions.length() - 1);
            // 设置用户的权限信息
            userInDB.setPermissions(permissions);
            // token载荷中不要放敏感信息
            userInDB.setPassword("");
            // 3.获取密钥
            PrivateKey privateKey = RsaUtils.getPrivateKey(ResourceUtils.getFile("classpath:rsa_pri").getPath());
            // 4. 颁发令牌
            String token = JwtUtils.generateTokenExpireInMinutes(userInDB, privateKey, 45);
            // 5. 没有异常正常返回
            return new ResultVO(true, "登录成功", token);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResultVO(false, "令牌不合法!!!");
        }
    }
  • 后端mapper层
 // 通过用户名查询用户
    @Select("select * from sys_user where user_name = #{userName}")
    public SysUser findUserByUserName(String userName);

    //查询用户的角色信息
    @Select("SELECT role.role_name FROM sys_user_role sur " +
            "LEFT JOIN sys_role role ON sur.role_id = role.role_code " +
            "WHERe sur.user_id = #{userId}")
    public List findRolesByUserId(String userId);

    // 查询用户权限信息
    @Select("SELECT per.perm_name FROM sys_user_role sur n" +
            "LEFT JOIN sys_role_permission srp ON sur.role_id = srp.role_idn" +
            "LEFT JOIN sys_permission per ON srp.perm_id = per.perm_coden" +
            "WHERe sur.user_id = 1;")
    public List findPermissionByUserId(Integer userId);
2. 配置信息
  • SpringSecurity的配置
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    // 放行静态资源
    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers(
                "/swagger-ui.html
router.beforeEach(async(to, from, next) => {
  // start progress bar
  NProgress.start()

  // set page title
  document.title = getPageTitle(to.meta.title)

  verify().then(res => {
    if (!res.success) {
      if (to.path === '/login') {
        next()
      } else {
        // 跳回登录页面
        next(`/login?redirect=${to.path}`)
        NProgress.done()
      }
    } else {
      // 放行
      next()
    }
  })
})

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/314301.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号