文章目錄
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