04 springsecurity完成vue界面的管理


前面我們了解了springboot與springsecurity的整合,也了解了springsecurity通過oauth2完成單點登錄。這一節我們將看一下springsecurity在前后端分離項目中的使用,也就是其對vue界面的保護和管理。

1、環境約束

  • idea2018.1
  • maven3.6.1

2、前提約束

3、操作步驟

3.1、創建前端項目

  • 創建vue項目,假設名稱為springsecurity-vue-ui
    https://www.jianshu.com/p/644eb12a8174
  • 在springsecurity-vue-ui/src文件夾下創建views文件夾
  • 在springsecurity-vue-ui/src/views文件夾下創建index.vue
<template>
  <div >
    用戶名: <input type="text" v-model="loginForm.username" />
    <br><br>
    密碼: <input type="text" v-model="loginForm.password" />
    <br><br>
    <input type="button" value="登錄" @click="login('loginForm')"/>
  </div>
</template>
<script>
  import axios from 'axios'

  axios.defaults.withCredentials = true //跨域
  axios.defaults.timeout = 10000
  axios.defaults.headers.post['Content-Type'] = 'application/x-www=form-urlencoded'
  export default {
    data () {
      return {
        loginForm: {
          username: 'zhangli',
          password: '123456',
        }
      }
    },
    methods:{
      login: function (){
        let _this = this;
        axios.post("/login?username="+this.loginForm.username+"&password="+this.loginForm.password)
          .then(function (response) {
            if(response.data.status="200")
            {
              window.location.href="/show"
            }
          })
          .catch(function (reason) {
            console.log(reason);
          })
      }
    }
  }
</script>
  • 修改springsecurity-vue-ui/router/index.js
import Vue from 'vue'
import Router from 'vue-router'
import HelloWorld from '@/components/HelloWorld'
import Index from '../views/index/index' 

Vue.use(Router)

export default new Router({
  routes: [
    {
      path: '/',
      name: 'HelloWorld',
      component: HelloWorld
    },
    // 配置路由地址
    {
      path: '/index',
      name: 'Index',
      component: Index
    }
  ]
})
  • 修改springsecurity-vue-ui/config/index.js中的proxyTable節點:
proxyTable: {
      '/login': {
        target: 'http://localhost:8082',
        '^/login':'/login'
      },
      '/show': {
        target: 'http://localhost:8082',
        '^/show':'/show'
      },
      '/logout': {
        target: 'http://localhost:8082',
        '^/logout':'/logout'
      }
    }
  • 下載包、打包以及啟動,執行以下命令:
cd springsecurity-vue-ui
# 下載包
cnpm install
# 打包
cnpm run build
# 啟動
cnpm run start
  • 訪問http://localhost:8080/#/index,得到以下界面:
    登錄界面

3.2、創建后端項目

  • 創建一個springboot項目,假設名稱為springsecurity-vue-server,pom.xml內容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.2.RELEASE</version>
        <relativePath/>
    </parent>
    <groupId>net.wanho</groupId>
    <artifactId>springsecurity_vue_server</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springsecurity_vue_server</name>
    <description>Demo project for Spring Boot</description>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-test</artifactId>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
        </dependency>
    </dependencies>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <repositories>
        <repository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </repository>
    </repositories>
    <pluginRepositories>
        <pluginRepository>
            <id>spring-releases</id>
            <name>Spring Releases</name>
            <url>https://repo.spring.io/libs-release</url>
        </pluginRepository>
    </pluginRepositories>

</project>
  • 在application.yml中設置端口:
server:
  port: 8082
  • 在主啟動類下創建UserInfo.java以記錄用戶信息

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

public class UserInfo implements UserDetails {
    private User user;
    private List<Role> roles;

    public List<Role> getRoles() {
        return roles;
    }

    public void setRoles(List<Role> roles) {
        this.roles = roles;
    }

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }

    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        if (roles == null || roles.isEmpty()) {
            return new ArrayList<>();
        }

        List<GrantedAuthority> authorities = new ArrayList<>();
        for (Role role : roles) {
            authorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
        }
        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;
    }

    public static class Role implements Serializable {
        private long id;
        private String name;

        public Role(long id, String name) {
            this.id = id;
            this.name = name;
        }

        public Role() {
        }

        public long getId() {
            return id;
        }

        public void setId(long id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }
    }

    public static class User implements Serializable {
        private Long id;
        private String username;
        private String password;

        public User(Long id, String username, String password) {
            this.id = id;
            this.username = username;
            this.password = password;
        }

        public User() {
        }

        public Long getId() {
            return id;
        }

        public void setId(Long id) {
            this.id = id;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }
    }
}
  • 在主啟動類下創建CorsConfig.java以完成跨域:

import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class CorsConfig implements WebMvcConfigurer {
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**")
                .allowedMethods("*")
                .allowedHeaders("*")
                .allowedOrigins("*");
    }
}
  • 在主啟動類下創建MyUserDetailService.java以獲取用戶信息,注意,我們這邊的用戶信息是寫死的。

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.List;

@Service
public class MyUserDetailService implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        UserInfo.User user = new UserInfo.User();
        user.setUsername("zhangli");
        user.setPassword("123456");
        List<UserInfo.Role> list = new ArrayList<>();
        UserInfo.Role role = new UserInfo.Role(1, "USER");
        list.add(role);
        UserInfo userDetail = new UserInfo();
        userDetail.setRoles(list);
        userDetail.setUser(user);
        if (userDetail == null) {
            throw new UsernameNotFoundException("Not found username:" + username);
        }
        return userDetail;
    }
}
  • 在主啟動類下創建MyAuthenticationProvider.java以驅動MyUserDetailService.java

import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Collection;

@Component
public class MyAuthenticationProvider implements AuthenticationProvider {

    @Resource
    private UserDetailsService userDetailService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String userName = authentication.getName();// 這個獲取表單輸入中返回的用戶名;
        String password = (String) authentication.getCredentials();// 這個是表單中輸入的密碼;
        UserInfo userInfo = (UserInfo) userDetailService.loadUserByUsername(userName); // 這里調用我們的自己寫的獲取用戶的方法;
        if (userInfo == null) {
            throw new BadCredentialsException("用戶名不存在");
        }
        if (!userInfo.getPassword().equals(password)) {
            throw new BadCredentialsException("密碼不正確");
        }
        Collection<? extends GrantedAuthority> authorities = userInfo.getAuthorities();
        return new UsernamePasswordAuthenticationToken(userInfo, password, authorities);
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}
  • 在主啟動類下創建WebSecurityConfig.java以設置web安全

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
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.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
import org.springframework.security.web.authentication.SimpleUrlAuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {


    @Resource
    MyAuthenticationProvider authenticationProvider;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .authorizeRequests()
                // 對登錄注冊要允許匿名訪問;
                .antMatchers("/login").permitAll()
                // 其他的路徑都要登錄之后具備USER角色
                .antMatchers("/**").hasRole("USER")
                //這里配置的loginProcessingUrl為頁面中對應表單的 action ,該請求為 post,並設置可匿名訪問
                .and().formLogin().loginProcessingUrl("/login").permitAll()
                //登錄成功后的返回結果
                .successHandler(new AuthenticationSuccessHandlerImpl())
                //登錄失敗后的返回結果
                .failureHandler(new AuthenticationFailureHandlerImpl())
                //這里配置的logoutUrl為登出接口,並設置可匿名訪問
                .and().logout().logoutUrl("/logout").permitAll()
                //登出后的返回結果
                .logoutSuccessHandler(new LogoutSuccessHandlerImpl())
                //這里配置的為當未登錄訪問受保護資源時,返回json,並且讓springsecurity自帶的登錄界面失效
                .and().exceptionHandling().authenticationEntryPoint(new AuthenticationEntryPointHandler());
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    //定義登陸成功返回信息
    private class AuthenticationSuccessHandlerImpl extends SimpleUrlAuthenticationSuccessHandler {
        @Override
        public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            UserInfo userInfo = (UserInfo) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"200\",\"msg\":\"登錄成功\"}");
            out.flush();
            out.close();
        }
    }

    //定義登出成功返回信息
    private class LogoutSuccessHandlerImpl extends SimpleUrlLogoutSuccessHandler {

        public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response,
                                    Authentication authentication) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"200\",\"msg\":\"登出成功\"}");
            out.flush();
            out.close();
        }
    }

    //定義登陸失敗返回信息
    private class AuthenticationFailureHandlerImpl extends SimpleUrlAuthenticationFailureHandler {
        @Override
        public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
            response.setContentType("application/json;charset=utf-8");
            PrintWriter out = response.getWriter();
            out.write("{\"status\":\"100\",\"msg\":\"請檢查用戶名、密碼或驗證碼是否正確\"}");
            out.flush();
            out.close();
        }
    }

    public class AuthenticationEntryPointHandler implements AuthenticationEntryPoint {
        @Override
        public void commence(HttpServletRequest httpServletRequest, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
            response.sendRedirect("http://localhost:8080/#/index");
        }
    }
}
  • 在主啟動下創建UserController.java以提供api
import com.alibaba.fastjson.JSONObject;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class UserController {

    @GetMapping("/show")
    public JSONObject show(){
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("status","200");
        jsonObject.put("data","this is the data");
        return jsonObject;
    }
}
  • 啟動springboot

3.3、測試

  • 訪問http://localhost:8080/#/index,點擊“登錄”,得到以下頁面
    登陸成功之后訪問/show
    注意,這里本應該是個頁面,但作者只提供了api訪問的響應結果
  • 打開一個新的標簽頁,訪問http://localhost:8080/#/logout,得到以下頁面
    訪問登出api成功的響應
  • 再次刷新之前的http://localhost:8080/show,則又重新顯示登錄頁面。
    以上就是springsecurity對vue界面的保護和管理。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM