SpringSecurity front-end and back-end separation

1. Create the vue front-end framework http://t.csdnimg.cn/jRcInicon-default.png?t= N7T8http://t.csdnimg.cn/jRcIn

After creation, use the tool to open and download axios, element-ui

Then import axios and element-ui in the global configuration. I also have interceptors and paging plug-ins.

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



// For back-end projects http://localhost:8080
//axios sets a default path
// Configure default values when creating an instance
const instance = axios.create({
  // Use a fake basic path when accessing the path
  baseURL: 'http://localhost:8080/'
});
Vue.prototype.$axios = instance;
Vue.use(ElementUI);

instance.interceptors.response.use( response=> {
  // status code 500
  if(response.data.code==500){
    // Jump to the login component
    router.push({path:"/login"});

    return;
  }
// Data is returned directly to axios
  return response.data.t;
}, error=> {
  // Status codes outside the 2xx range will trigger this function.
  // Do something with the response error
  return Promise.reject(error);
});

// paging
//------------------
//Introduce components
import page from '@/views/util/page.vue';

//global component
Vue.component("my-fenye",page);
//---------------------

A front-end login page (with a background image to be changed)

<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="username" prop="username">
        <el-input type="text" v-model="ruleForm.username" autocomplete="off"></el-input>
      </el-form-item>
      <el-form-item label="Confirm password" 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')">Submit</el-button>
        <el-button @click="resetForm('ruleForm')">Reset</el-button>
      </el-form-item>
    </el-form>
  </div>


</template>


<script>


export default {
  data() {
    var checkName = (rule, value, callback) => {
      if (!value) {
        return callback(new Error('The name cannot be empty'));
      }else{
        callback();
      }


    };
    var validatePass = (rule, value, callback) => {
      if (value === '') {
        callback(new Error('Please enter password'));
      } 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; /* Top and bottom spacing 160px, left and right automatically centered*/
  background-color: rgb(255, 255, 255,0.8); /* Transparent background color */
  padding: 30px;
  border-radius: 20px; /* rounded corners */
}


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


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

</style>

2. Obtain data

Download qs splicing data

Access backend data

This is a cross domain issue 302

Add http.cors() to the backend Security configuration;

I visited again and found that it still didn’t work. I found that there was a problem in the global configuration.

Returned If there is a problem with the data, just delete the data.t at the end.

now it’s right

1. Front-end and back-end authentication response data

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Start configuring customized information
        http.formLogin()
                .loginPage("/login.html")
                .loginProcessingUrl("/userlogin")// The login path can be consistent with the login path in html or jsp
                .successHandler(new AuthenticationSuccessHandler() {
                    /**
                     * Authentication successful
                     * @param request request object
                     * @param response object of response
                     * @param authentication authentication information
                     * @throwsIOException
                     * @throwsServletException
                     */
                    @Override
                    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
                        //Authentication successful
                        //code 200 msg successful login t:null
                        Result result = new Result(200,"Login successful",null);
                        ObjectMapper objectMapper = new ObjectMapper();
                        //Use ObjectMapper to convert result into json string
                        String s = objectMapper.writeValueAsString(result);
                        //Response json data
                        PrintWriter writer = response.getWriter();
                        writer.println(s);
                        writer.flush();//Refresh
                        writer.close();//Close
                    }
                })//When performing front-end and back-end authentication, the authentication method is successful.
        ;
        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();//Except for paths that do not require authentication, all other paths require authentication
        http.csrf().disable(); // Turn off csrf protection
        http.cors();//Can cross domain
    }

@Resource
private UserDetailsService userDetailsService;
@Bean
public PasswordEncoder getPassword(){
    return new BCryptPasswordEncoder();
}
    //Customize user information
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception{
        auth.userDetailsService(userDetailsService).passwordEncoder(getPassword());
    }
}

Log in after setting up

Authentication successful (I messed up the code) add the following sentence

Authentication failed:

I encapsulated the same things in success and failure into a method

Test certification failed

A duplicate navigation issue occurred

The solution is as follows: put it under index.js

//Aiming at the problem of repeated navigation errors in the ElementUI navigation bar
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
  return originalPush.call(this, location).catch(err => err)
}

Because the interceptor is set and it is not 200, it is intercepted.

So we can only intercept the output here.

2. Visit the page

Create a main page and find one in 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>Navigation 1</template>
          <el-menu-item-group>
            <el-menu-item index="/test">test</el-menu-item>
            <el-menu-item index="1-2">Option 2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group>
            <el-menu-item index="1-3">Option 3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="1-4">
            <template slot="title">Option 4</template>
            <el-menu-item index="1-4-1">Option 4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="2">
          <template slot="title"><i class="el-icon-menu"></i>Navigation 2</template>
          <el-menu-item-group>
            <template slot="title">Group 1</template>
            <el-menu-item index="2-1">Option 1</el-menu-item>
            <el-menu-item index="2-2">Option 2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="Group 2">
            <el-menu-item index="2-3">Option 3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="2-4">
            <template slot="title">Option 4</template>
            <el-menu-item index="2-4-1">Option 4-1</el-menu-item>
          </el-submenu>
        </el-submenu>
        <el-submenu index="3">
          <template slot="title"><i class="el-icon-setting"></i>Navigation Three</template>
          <el-menu-item-group>
            <template slot="title">Group 1</template>
            <el-menu-item index="3-1">Option 1</el-menu-item>
            <el-menu-item index="3-2">Option 2</el-menu-item>
          </el-menu-item-group>
          <el-menu-item-group title="Group 2">
            <el-menu-item index="3-3">Option 3</el-menu-item>
          </el-menu-item-group>
          <el-submenu index="3-4">
            <template slot="title">Option 4</template>
            <el-menu-item index="3-4-1">Option 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>

Log in to main if successful

3. Store in cookie

In main.js

in cross-domain files

Then when I try to log in again, a cross-domain problem occurs.

solve!

Response data again

This is the data inside (the content inside is in the database)

3. Set permissions for user

403 No permission

三.jwt

Json web token (JWT) is an open standard based on JSON (RFC7519) for conveying claims between web application environments. The token is designed to be compact and secure, especially suitable for Single sign-on (SSO) scenario for distributed sites ==. JWT claims are generally used to pass authenticated user identity information between identity providers and service providers to facilitate obtaining resources from resource servers. You can also add some For additional declaration information necessary for other business logic, the token can also be used directly for authentication or encrypted.

Generate credential information

Header

The Header part is a JSON object describing the metadata of the JWT, which usually looks like the following.

{

“alg”: “HS256”,

“typ”: “JWT”

}

Payload

The Payload part is also a JSON object, == used to store the actual data that needs to be transferred==. JWT specifies 7 official fields for selection.

iss (issuer): issuer

exp (expiration time): expiration time

sub (subject): subject

aud (audience): audience

nbf (Not Before): effective time

iat (lssued At):Issuance time

jti (JWT ID): number

In addition to official fields, you can also define private fields in this section. Here is an example.

{

“sub”: “1234567890”,

“name” : “John Doe”,

“userid”:2

“admin”: true

}

Note that JWT is not encrypted by default and can be read by anyone, so do not put ==secret information== in this section. This JSON object must also be converted into a string using the Base64URL algorithm.

Signaretu

Signature is a signature of the first two parts to prevent data tampering.

First, you need to specify a secret. This key is only known to the server and cannot be leaked to the user. Then, use the ==signature algorithm specified in the Header (the default is HMAC SHA256)== to generate a signature according to the following formula.

HMACSHA256(

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

secret)

After calculating the signature, combine the three parts of Header, Payload, and Signature into a string, and separate each part with “dot” (.) before returning it to the user.

Add dependencies to the project

<!-- Add hutool dependency to the project -->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.8.16</version>
        </dependency>

Generate certificate

The first and second parts are not encrypted and use the base64 encoding format. The original data can be obtained by reverse encoding through the website.

Base64 online encoding and decoding | Base64 encryption and decryption – Base64.us

Set time

After it is automatically generated, you can delete it automatically stored in the cookie.

Get a request connector

View stored tokens

Find the request header

Yes, but I can’t log in

Give him an interceptor

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 {
        //parse token
        /**
         * 1. Get token
         * There is analysis
         * No return json without authentication
         * 2.Yes
         * 2.1 Verification token
         */
// Get token
        String token = request.getHeader("token");
        //tokent is not empty
        if (StringUtils.isNotBlank(token)){
            //parse
            boolean verify = JWTUtil.verify(token, "pxy".getBytes());
            if (verify){
                //Verification passed
                //Get the user's name and password
                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);
                //Save user information
                SecurityContextHolder.getContext().setAuthentication(usertoken);//release
                filterChain.doFilter(request,response);
            }
        }else {
            Result result = new Result(401, "Not logged in", null);
            extracted(response,result);
        }
    }


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

        response.setContentType("application/json;charset=utf8");
        ObjectMapper objectMapper = new ObjectMapper();
        //Use ObjectMapper to convert result into json string
        String s = objectMapper.writeValueAsString(result);
        //Response json data
        PrintWriter writer = response.getWriter();
        writer.println(s);
        writer.flush();//Refresh
        writer.close();//Close
    }
}

JwtFilter: