Spring Boot(九)整合Spring Security實現動態權限控制

Spring Security簡介

安全框架,權限管理
官方文檔

項目結構

在這裏插入圖片描述

Springboot中 Spring Security的使用

引入依賴

 <dependencies>
        <!--引入security依賴-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <!-- springboot整合freemarker -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-freemarker</artifactId>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>${mysql.version}</version>
        </dependency>
        <!--alibaba的druid數據庫連接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>${druid.version}</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>${mybatis.version}</version>
        </dependency>
    </dependencies>

核心依賴爲:

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

數據庫表設計

總共五張表:
權限表、用戶表、角色表、用戶角色表、角色權限表
在這裏插入圖片描述

application.yml配置信息

server:
  port: 8011
  servlet:
    context-path: /shopping-security
spring:
  application:
    name: shopping-security

  freemarker:
    # 設置模板後綴名
    suffix: .ftl
    # 設置文檔類型
    content-type: text/html
    # 設置頁面編碼格式
    charset: UTF-8
    # 設置頁面緩存
    cache: false
    # 設置ftl文件路徑
    template-loader-path:
      - classpath:/templates
    request-context-attribute: request
    # 設置靜態文件路徑,js,css等

  mvc:
    static-path-pattern: /static/**
  datasource:
    url: jdbc:mysql://127.0.0.1:3306/security?useUnicode=true&characterEncoding=utf-8&useSSL=true&serverTimezone=UTC
    username: root
    password: 123456
    # druid 連接池
    type: com.alibaba.druid.pool.DruidDataSource
    driver-class-name: com.mysql.jdbc.Driver

spirngsecurity核心配置類

  • SpringSecurityConf
@Component
@EnableWebSecurity
@Slf4j
public class SpringSecurityConf extends WebSecurityConfigurerAdapter {

    @Autowired
    private PermissionMapper permissionMapper;
    @Autowired
    private MyUserDetailService myUserDetailService;


    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailService).passwordEncoder(new PasswordEncoder() {

            @Override
            public boolean matches(CharSequence rawPassword, String encodedPassword) {
                String encode = MD5Util.encode((String) rawPassword);
                encodedPassword=encodedPassword.replace("\r\n", "");
                boolean result = encodedPassword.equals(encode);
                return result;
            }
            @Override
            public String encode(CharSequence rawPassword) {
                return MD5Util.encode((String) rawPassword);
            }
        });
    }


    /**
     *
     * @param http
     * @throws Exception
     *
     */
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //查詢所有權限,動態權限認證
        List<Permission> permissions = permissionMapper.findAllPermission();
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry authorizeRequests = http
                .authorizeRequests();
        permissions.forEach(permission ->
        {
            log.info("獲取權限爲" + permission.getPermTag());
            authorizeRequests.antMatchers(permission.getUrl()).hasAnyAuthority(permission.getPermTag());
        });
        authorizeRequests.
                antMatchers("/login").permitAll().// 登錄跳轉 URL 無需認證
                antMatchers("/**").
                fullyAuthenticated().
                and().
                formLogin()//表單認證
                .loginPage("/login").
                and().csrf().disable();
    }




}
  • MyUserDetailService
package com.zou.security.service;

import com.zou.security.mapper.UserMapper;
import com.zou.security.module.Permission;
import com.zou.security.module.User;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
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.Component;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;

import java.util.ArrayList;
import java.util.List;

/**
 * @author WH
 * @version 1.0
 * @date 2019/12/26 20:01
 */
@Component
@Slf4j
public class MyUserDetailService implements UserDetailsService {
    @Autowired
    private UserMapper userMapper;

    /**
     * 認證  用戶登入會先被攔截到這個頁面
     * @param username
     * @return
     * @throws UsernameNotFoundException
     */
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        //根據用戶名查詢用戶信息
        User user = userMapper.findByUsername(username);
        if (ObjectUtils.isEmpty(user)) {
            log.info("用戶" + username +"不存在");
            throw new UsernameNotFoundException("用戶不存在");
        }
        //查詢用戶權限
        List<GrantedAuthority> authorities = new ArrayList<>();
        List<Permission> permissions = userMapper.findPermissionByUsername(username);
        permissions.forEach(permission ->
                authorities.add(new SimpleGrantedAuthority(permission.getPermTag())));
        //設置用戶權限
        user.setAuthorities(authorities);
        return user;


    }
}

查詢用戶權限核心mapper

  • UserMapper
package com.zou.security.mapper;

import com.zou.security.module.Permission;
import com.zou.security.module.User;
import org.apache.ibatis.annotations.Param;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface UserMapper {

	/**
	 * 查詢用戶信息
	 * @param userName
	 * @return
	 */
	@Select(" select * from sys_user where username = #{userName}")
	User findByUsername(@Param("userName") String userName);


	/**
	 * 查詢用戶的權限
	 * @param userName
	 * @return
	 */
	@Select(" select permission.* from sys_user user" + " inner join sys_user_role user_role"
			+ " on user.id = user_role.user_id inner join "
			+ "sys_role_permission role_permission on user_role.role_id = role_permission.role_id "
			+ " inner join sys_permission permission on role_permission.perm_id = permission.id where user.username = #{userName};")
	List<Permission> findPermissionByUsername(@Param("userName") String userName);
}

  • PermissionMapper
package com.zou.security.mapper;

import com.zou.security.module.Permission;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface PermissionMapper {

	@Select(" select * from sys_permission ")
	List<Permission> findAllPermission();

}

UserDetails

  • user
package com.zou.security.module;

import lombok.Data;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * @author wh
 * @version 1.0
 * @date 2019-12-25 10:04
 */
@Data
public class User implements UserDetails {
    /**
     * 主鍵
     */
    private Integer id;
    /**
     * 用戶名
     */
    private String username;
    /**
     * 別名
     */
    private String realname;
    /**
     *密碼
     */
    private String password;
    /**
     *創建時間
     */
    private Date createDate;
    /**
     *最後登入時間
     */
    private Date lastLoginTime;
    /**
     *
     */
    private boolean enabled;
    private boolean accountNonExpired;
    private boolean accountNonLocked;
    private boolean credentialsNonExpired;
    /**
     * 用戶所有權限
     */
    private List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

    /**
     * 封裝了權限信息
     * @return
     */
    @Override
    public Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities;
    }

}

設置springboot自定義錯誤頁面

  • WebServerAutoConfiguration
package com.zou.security.config;

import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.server.ErrorPage;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpStatus;

/**
 * 自定義 WEB 服務器參數 可以配置默認錯誤頁面
 * @author WH
 * @version 1.0
 * @date 2019/12/26 19:48
 */
@Configuration
public class WebServerAutoConfiguration {

    @Bean
    public ConfigurableServletWebServerFactory webServerFactory() {
        TomcatServletWebServerFactory factory = new TomcatServletWebServerFactory();
        ErrorPage errorPage400 = new ErrorPage(HttpStatus.BAD_REQUEST, "/error/400");
        ErrorPage errorPage401 = new ErrorPage(HttpStatus.UNAUTHORIZED, "/error/401");
        ErrorPage errorPage403 = new ErrorPage(HttpStatus.FORBIDDEN, "/error/403");
        ErrorPage errorPage404 = new ErrorPage(HttpStatus.NOT_FOUND, "/error/404");
        ErrorPage errorPage415 = new ErrorPage(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "/error/415");
        ErrorPage errorPage500 = new ErrorPage(HttpStatus.INTERNAL_SERVER_ERROR, "/error/500");
        factory.addErrorPages(errorPage400, errorPage401, errorPage403, errorPage404, errorPage415, errorPage500);
        return factory;
    }

}

  • ErrorController
package com.zou.security.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @author WH
 * @version 1.0
 * @date 2019/12/26 19:47
 */
@Controller
public class ErrorController {

	// 403權限不足頁面
	@RequestMapping("/error/403")
	public String error() {
		return "/error/403";
	}

}

訂單測試OrderController

package com.zou.security.controller;

import com.zou.security.mapper.UserMapper;
import com.zou.security.module.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * @author WH
 * @version 1.0
 * @date 2019/12/26 19:47
 */
@Controller
public class OrderController {

    @Autowired
    private UserMapper userMapper;
    // 首頁
    @RequestMapping("/")
    public String index() {
        return "index";
    }

    // 查詢訂單
    @RequestMapping("/showOrder")
    public String showOrder() {
        return "showOrder";
    }

    // 添加訂單
    @RequestMapping("/addOrder")
    public String addOrder() {
        return "addOrder";
    }

    // 修改訂單
    @RequestMapping("/updateOrder")
    public String updateOrder() {
        return "updateOrder";
    }

    // 刪除訂單
    @RequestMapping("/deleteOrder")
    public String deleteOrder() {
        return "deleteOrder";
    }

    // 自定義登陸頁面
    @GetMapping("/login")
    public String login() {
        return "login";
    }



    @RequestMapping("/findUser")
    @ResponseBody
    public User findUser(String userName) {
        return userMapper.findByUsername(userName);
    }
}

啓動類:SecurityApplication

  • SecurityApplication
package com.zou.security;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author wh
 * @version 1.0
 * @date 2019-12-25 9:37
 */
@SpringBootApplication
@MapperScan("com.zou.security.mapper")
public class SecurityApplication {


    public static void main(String[] args) {
        SpringApplication.run(SecurityApplication.class, args);
    }
}

測試

訪問: http://localhost:8011/shopping-security/login
賬號密碼:user        123456
在這裏插入圖片描述

在這裏插入圖片描述

訪問查詢訂單,可以正常訪問,訪問刪除訂單,顯示權限不足

##項目源碼
源碼及SQL

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章