SpringSecurity 前后端分离

一.创建vue前端框架http://t.csdnimg.cn/jRcInicon-default.png?t=N7T8http://t.csdnimg.cn/jRcIn

创建之后使用工具打开然后下载axios ,element-ui

再在全局配置里面导入axios,element-ui 我这里还有拦截器,还有使用的分页插件

import axios from "axios";
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';



// 后端项目的时候  http://localhost:8080
// axios设置一个默认的路径
// 创建实例时配置默认值
const instance = axios.create({
  // 访问路径的时候假的一个基础的路径
  baseURL: 'http://localhost:8080/'
});
Vue.prototype.$axios = instance;
Vue.use(ElementUI);

instance.interceptors.response.use( response=> {
  // 状态码  500
  if(response.data.code==500){
    // 跳转到 login 组件里面
    router.push({path:"/login"});

    return;
  }
// 数据 直接返回给axios
  return response.data.t;
}, error=> {
  // 超出 2xx 范围的状态码都会触发该函数。
  // 对响应错误做点什么
  return Promise.reject(error);
});

// 分页
//-------------------
// 引入组件
import page from '@/views/util/page.vue';

//全局组件
Vue.component("my-fenye",page);
//--------------------

一个前端登陆页面(有一个背景图要改)

<template>


  <div class="login-container">
    <el-form :model="ruleForm" status-icon :rules="rules" ref="ruleForm" label-width="100px" class="login-form">
      <el-form-item label="用户名" prop="username">
        <el-input type="text" v-model="ruleForm.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="确认密码" prop="password">
        <el-input type="password" v-model="ruleForm.password" autocomplete="off"></el-input>
      </el-form-item>


      <el-form-item>
        <el-button type="primary" @click="submitForm('ruleForm')">提交</el-button>
        <el-button @click="resetForm('ruleForm')">重置</el-button>
      </el-form-item>
    </el-form>
  </div>


</template>


<script>


export default {
  data() {
    var checkName = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('名字不能为空'));
      }else{
        callback();
      }


    };
    var validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('请输入密码'));
      } else {
        callback();
      }
    };


    return {
      ruleForm: {
        username: '',
        password: '',


      },
      rules: {
        password: [
          { validator: validatePass, trigger: 'blur' }
        ],


        username: [
          { validator: checkName, trigger: 'blur' }
        ]
      }
    };
  },
  methods: {
    submitForm(formName) {
      this.$refs[formName].validate((valid) => {
        if (valid) {
          alert('submit!');

        } else {
           console.log('error submit!!');
        }
      });
    },
    resetForm(formName) {
      this.$refs[formName].resetFields();
    }
  }
}
</script>


<style scoped>


.login-form {
  width: 350px;
  margin: 160px auto; /* 上下间距160px,左右自动居中*/
  background-color: rgb(255, 255, 255,0.8); /* 透明背景色 */
  padding: 30px;
  border-radius: 20px; /* 圆角 */
}


/* 背景 */
.login-container {
  position: absolute;
  width: 100%;
  height: 100%;
  background: url("../assets/timg.png");
}


/* 标题 */
.login-title {
  color: #303133;
  text-align: center;
}

</style>

二.获取数据

下载qs拼接数据

访问后端数据

这是跨域问题302

在后端Security配置里加入http.cors();

再次访问发现还是不行发现是全局配置里面有问题

返回的数据有问题把后面的data.t删掉就行了

这就对了

1.前后端认证响应数据

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 开始 配置自定义的信息
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/userlogin")// 登录的路径 跟html或者jsp中的登录路径保持一致即可
                .successHandler(new AuthenticationSuccessHandler() {
                    /**
                     * 认证成功
                     * @param request 请求对象
                     * @param response 响应的对象
                     * @param authentication 认证的信息
                     * @throws IOException
                     * @throws ServletException
                     */
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //认证成功
                        //code 200 msg 登陆成功 t:null
                        Result result = new Result(200,"登陆成功",null);
                        ObjectMapper objectMapper = new ObjectMapper();
                        //使用ObjectMapper将result转化成json字符串
                        String s = objectMapper.writeValueAsString(result);
                        //响应json数据
                        PrintWriter writer = response.getWriter();
                        writer.println(s);
                        writer.flush();//刷新
                        writer.close();//关闭
                    }
                })//前后端认证的时候 认证成功 走的方法
        ;
        http.authorizeRequests().antMatchers("userlogin").permitAll();


        http.exceptionHandling().accessDeniedPage("/403.html");
//        http.authorizeRequests().antMatchers("/test").hasRole("USER");

//        http.authorizeRequests().antMatchers("/test").hasAuthority("testppp");
        http.authorizeRequests().anyRequest().authenticated();// 除去不需要认证的路径的其它路径都需要认证
        http.csrf().disable();// 关闭csrf的保护
        http.cors();//可以跨域
    }

@Resource
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder getPassword(){
    return new BCryptPasswordEncoder();
}
    // 自定义用户的信息
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(getPassword());
    }
}

设置完再登陆

认证成功(????是我乱码了)加入下面一句

认证失败:

我把成功和失败里的相同的封装成一个方法

测试认证失败

出现一个重复导航问题

解决如下:要放到index.js下面

// 针对ElementUI导航栏中重复导航报错问题
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}

因为设置了拦截器不是200就被拦截

所以只能在拦截这里是输出

2.访问页面

创建一个main页面 在element 里面找了一个

<script setup>

</script>

<template>

  <el-container  style="height: 500px; border: 1px solid #eee">
    <el-aside width="200px" style="background-color: rgb(238, 241, 246)">
      <el-menu :router="true">
        <el-submenu index="1">
          <template slot="title"><i class="el-icon-message"></i>导航一</template>
          <el-menu-item-group>
            <el-menu-item index="/test">test</el-menu-item>
            <el-menu-item index="1-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group>
            <el-menu-item index="1-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="1-4">
            <template slot="title">选项4</template>
            <el-menu-item index="1-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="2">
          <template slot="title"><i class="el-icon-menu"></i>导航二</template>
          <el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="2-1">选项1</el-menu-item>
            <el-menu-item index="2-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分组2">
            <el-menu-item index="2-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="2-4">
            <template slot="title">选项4</template>
            <el-menu-item index="2-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="3">
          <template slot="title"><i class="el-icon-setting"></i>导航三</template>
          <el-menu-item-group>
            <template slot="title">分组一</template>
            <el-menu-item index="3-1">选项1</el-menu-item>
            <el-menu-item index="3-2">选项2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="分组2">
            <el-menu-item index="3-3">选项3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="3-4">
            <template slot="title">选项4</template>
            <el-menu-item index="3-4-1">选项4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
      </el-menu>
    </el-aside>

    <!---->
    <el-container>
      <el-header>Header</el-header>
      <el-main>
        <router-view></router-view>
      </el-main>
      <el-footer>Footer</el-footer>
    </el-container>
  </el-container>
</template>

<style scoped>
.el-header {
  background-color: #B3C0D1;
  color: #333;
  line-height: 60px;
}

.el-aside {
  color: #333;
}
.el-header, .el-footer {
  background-color: #B3C0D1;
  color: #333;
  text-align: center;
  line-height: 60px;
}

.el-aside {
  background-color: #D3DCE6;
  color: #333;
  text-align: center;
  line-height: 200px;
}

.el-main {
  background-color: #E9EEF3;
  color: #333;
  text-align: center;
  line-height: 160px;
}

body > .el-container {
  margin-bottom: 40px;
}

.el-container:nth-child(5) .el-aside,
.el-container:nth-child(6) .el-aside {
  line-height: 260px;
}

.el-container:nth-child(7) .el-aside {
  line-height: 320px;
}
</style>

成功就登陆main

3.存放到cookie里

在main.js

在跨域文件里

然后再访问登陆就出现了跨域问题

解决!

再响应数据

这是里面的数据(里面的内容是再数据库里)

3.给user设置个权限

403没有权限

三.jwt

Json web token (JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519).该token被设计为紧凑且==安全==的,特别适用于==分布式站点的单点登录(SSO)场景==。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

生成凭证信息

Header

Header 部分是一个JSON对象,描述JWT的元数据,通常是下面的样子。

{

"alg": "HS256",

"typ": "JWT"

}

Payload(荷载)

Payload 部分也是一个JSON对象,==用来存放实际需要传递的数据==。JWT规定了7个官方字段,供选用。

iss (issuer):签发人

exp (expiration time):过期时间

sub (subject):主题

aud (audience):受众

nbf (Not Before):生效时间

iat (lssued At):签发时间

jti (JWT ID):编号

除了官方字段,==你还可以在这个部分定义私有字段==,下面就是一个例子。

{

"sub": "1234567890",

"name" : "John Doe",

“userid”:2

"admin": true

}

注意,JWT 默认是不加密的,任何人都可以读到,所以不要把==秘密信息==放在这个部分。这个JSON 对象也要使用Base64URL 算法转成字符串。

Signaretu

Signature是对前两部分的签名,防止数据篡改。

首先,需要指定一个==密钥(secret)==。这个密钥只有==服务器才知道==,不能泄露给用户。然后,使用Header里面指定的==签名算法(默认是 HMAC SHA256)==,按照下面的公式产生签名。

HMACSHA256(

base64UrlEncode(header) + ".”"+base64UrlEncode(payload),

secret)

算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。

再项目里添加依赖

<!--        项目添加hutool依赖-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>

生成认证

第一部分和第二部分 并能没有加密  使用的是base64编码格式 通过网站 进行反编码就可以得出原来的数据

Base64 在线编码解码 | Base64 加密解密 - Base64.us

设置时间

自动生成之后就可以把自动存放到cookie删除了

弄个请求连接器

查看存储的token

找请求头

有,但是登陆不进去

给他一个拦截器

package com.aaa.config;

import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTUtil;
import com.aaa.util.Result;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;
import java.util.stream.Collectors;

@Component
public class JwtFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        //解析token
        /**
         * 1.获取token
         *  有 解析
         *  没有 返回json 没有认证
         * 2.有
         *  2.1校验token
         */
//        获取token
        String token = request.getHeader("token");
        //tokent 不为空
        if (StringUtils.isNotBlank(token)){
            //解析
            boolean verify = JWTUtil.verify(token, "pxy".getBytes());
            if (verify){
                //校验合格
                //获取用户的名字 密码
                JWT jwt = JWTUtil.parseToken(token);
                String username = (String) jwt.getPayload("username");
                List<String> resources = (List<String>) jwt.getPayload("resources");
                List<SimpleGrantedAuthority>  collect = resources.stream().map(s->new SimpleGrantedAuthority(s)).collect(Collectors.toList());

                UsernamePasswordAuthenticationToken usertoken = new UsernamePasswordAuthenticationToken(username, null, collect);
                // 存起来用户的信息
                SecurityContextHolder.getContext().setAuthentication(usertoken);//放行
                filterChain.doFilter(request,response);
            }
        }else {
            Result result = new Result(401, "没有登陆", null);
            extracted(response,result);
        }
    }


    private void extracted(HttpServletResponse response, Result result) throws IOException {

        response.setContentType("application/json;charset=utf8");
        ObjectMapper objectMapper = new ObjectMapper();
        //使用ObjectMapper将result转化成json字符串
        String s = objectMapper.writeValueAsString(result);
        //响应json数据
        PrintWriter writer = response.getWriter();
        writer.println(s);
        writer.flush();//刷新
        writer.close();//关闭
    }
}

JwtFilter:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值