文章目录
管理后台
1. 搭建项目
1.1 新建maven工程 blog-admin
<?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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>blog-parent2</artifactId>
<groupId>com.mszlu</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>blog-admin</artifactId>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
<!-- 排除 默认使用的logback -->
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<!-- log4j2 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-log4j2</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-mail</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>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.76</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.10.10</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
1.2 配置
application.properties:
server.port=8889
spring.application.name=hmx_admin_blog
#数据库的配置
# datasource
spring.datasource.url=jdbc:mysql://localhost:3306/blog?useUnicode=true&characterEncoding=UTF-8&serverTimeZone=UTC
spring.datasource.username=root
spring.datasource.password=root
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#mybatis-plus
mybatis-plus.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
mybatis-plus.global-config.db-config.table-prefix=ms_
# 上传文件总的最大值
spring.servlet.multipart.max-request-size=20MB
# 单个文件的最大值
spring.servlet.multipart.max-file-size=2MB
mybatis-plus配置:
package com.hmx.blog.admin.config;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
//扫包,将此包下的接口生成代理实现类,并且注册到spring容器中
@MapperScan("com.hmx.blog.admin.mapper")
public class MybatisPlusConfig {
//分页插件
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor(){
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor());
return interceptor;
}
}
1.3 启动类
package com.hmx.blog.admin;
import com.alibaba.fastjson.annotation.JSONField;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class AdminApplication {
public static void main(String[] args) {
SpringApplication.run(AdminApplication.class,args);
}
}
1.4 导入前端工程
放入resources下的static目录中,前端工程在资料中有
1.5 新建表
CREATE TABLE `blog`.`ms_admin` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
CREATE TABLE `blog`.`ms_permission` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`path` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
`description` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
CREATE TABLE `blog`.`ms_admin_permission` (
`id` bigint(0) NOT NULL AUTO_INCREMENT,
`admin_id` bigint(0) NOT NULL,
`permission_id` bigint(0) NOT NULL,
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_unicode_ci ROW_FORMAT = Dynamic;
2. 权限管理
2.1 Controller
package com.hmx.blog.admin.controller;
import com.hmx.blog.admin.pojo.Permission;
import com.hmx.blog.admin.vo.Result;
import com.hmx.blog.admin.model.params.PageParam;
import com.hmx.blog.admin.service.PermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-18 13:23
**/
@RestController
@RequestMapping("admin")
public class AdminController {
@Autowired
private PermissionService permissionService;
@PostMapping("permission/permissionList")
public Result permissionList(@RequestBody PageParam pageParam){
return permissionService.listPermission(pageParam);
}
@PostMapping("permission/add")
public Result add(@RequestBody Permission permission){
return permissionService.add(permission);
}
@PostMapping("permission/update")
public Result update(@RequestBody Permission permission){
return permissionService.update(permission);
}
@GetMapping("permission/delete/{id}")
public Result delete(@PathVariable("id") Long id){
return permissionService.delete(id);
}
}
package com.hmx.blog.admin.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class Permission {
@TableId(type = IdType.AUTO)
private Long id;
private String name;
private String path;
private String description;
}
package com.hmx.blog.admin.model.params;
import lombok.Data;
@Data
public class PageParam {
private Integer currentPage;
private Integer pageSize;
private String queryString;
}
2.2 Service
package com.hmx.blog.admin.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmx.blog.admin.mapper.PermissionMapper;
import com.hmx.blog.admin.model.params.PageParam;
import com.hmx.blog.admin.pojo.Permission;
import com.hmx.blog.admin.vo.PageResult;
import com.hmx.blog.admin.vo.Result;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-18 13:32
**/
@Service
public class PermissionService {
@Autowired
private PermissionMapper permissionMapper;
public Result listPermission(PageParam pageParam) {
/**
要的数据, 管理台 表的所有字段 Permission
*/
Page<Permission> page = new Page<>(pageParam.getCurrentPage(),pageParam.getPageSize());
LambdaQueryWrapper<Permission> queryWrapper = new LambdaQueryWrapper<>();
if (StringUtils.isNotBlank(pageParam.getQueryString())) {
queryWrapper.eq(Permission::getName,pageParam.getQueryString());
}
Page<Permission> permissionPage = permissionMapper.selectPage(page, queryWrapper);
PageResult<Permission> pageResult = new PageResult<>();
pageResult.setList(permissionPage.getRecords());
pageResult.setTotal(permissionPage.getTotal());
return Result.success(pageResult);
}
public Result add(Permission permission) {
this.permissionMapper.insert(permission);
return Result.success(null);
}
public Result update(Permission permission) {
this.permissionMapper.updateById(permission);
return Result.success(null);
}
public Result delete(Long id) {
this.permissionMapper.deleteById(id);
return Result.success(null);
}
}
package com.hmx.blog.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hmx.blog.admin.pojo.Permission;
import java.util.List;
public interface PermissionMapper extends BaseMapper<Permission> {
}
package com.hmx.blog.admin.vo;
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class Result {
private boolean success;
private int code;
private String msg;
private Object data;
public static Result success(Object data){
return new Result(true,200,"success",data);
}
public static Result fail(int code, String msg){
return new Result(false,code,msg,null);
}
}
package com.hmx.blog.admin.vo;
import lombok.Data;
import java.util.List;
@Data
public class PageResult<T> {
private List<T> list;
private Long total;
}
2.3 测试
3. Security集成
3.1 添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
3.2 配置
package com.hmx.blog.admin.config;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
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.builders.WebSecurity;
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.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
public static void main(String[] args) {
//加密策略 MD5 不安全 彩虹表 MD5 加盐
String hmx = new BCryptPasswordEncoder().encode("hmx");
System.out.println(hmx);
}
@Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests() //开启登录认证
// .antMatchers("/user/findAll").hasRole("admin") //访问接口需要admin的角色
.antMatchers("/css/**").permitAll()
.antMatchers("/img/**").permitAll()
.antMatchers("/js/**").permitAll()
.antMatchers("/plugins/**").permitAll()
.antMatchers("/admin/**").access("@authService.auth(request,authentication)") //自定义service 来去实现实时的权限认证
.antMatchers("/pages/**").authenticated()
.and().formLogin()
.loginPage("/login.html") //自定义的登录页面
.loginProcessingUrl("/login") //登录处理接口
.usernameParameter("username") //定义登录时的用户名的key 默认为username
.passwordParameter("password") //定义登录时的密码key,默认是password
.defaultSuccessUrl("/pages/main.html")
.failureUrl("/login.html")
.permitAll() //通过 不拦截,更加前面配的路径决定,这是指和登录表单相关的接口 都通过
.and().logout() //退出登录配置
.logoutUrl("/logout") //退出登录接口
.logoutSuccessUrl("/login.html")
.permitAll() //退出登录的接口放行
.and()
.httpBasic()
.and()
.csrf().disable() //csrf关闭 如果自定义登录 需要关闭
.headers().frameOptions().sameOrigin();
}
}
3.3 登录认证
package com.hmx.blog.admin.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.Data;
@Data
public class Admin {
@TableId(type = IdType.AUTO)
private Long id;
private String username;
private String password;
}
package com.hmx.blog.admin.service;
import com.hmx.blog.admin.pojo.Admin;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.userdetails.User;
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 java.util.ArrayList;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-19 12:15
**/
@Component
public class SecurityUserService implements UserDetailsService {
@Autowired
private AdminService adminService;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
//登陆的时候,会把username 传递到这里
//通过username查询 admin表,如果 admin存在 将密码告诉spring security
//如果不存在 返回null 认证失败了
Admin admin = adminService.findAdminByUsername(username);
if (admin == null) {
//登陆失败
return null;
}
UserDetails userDetails = new User(username,admin.getPassword(),new ArrayList<>());
return userDetails;
}
}
package com.hmx.blog.admin.service;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.hmx.blog.admin.mapper.AdminMapper;
import com.hmx.blog.admin.pojo.Admin;
import com.hmx.blog.admin.pojo.Permission;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-19 12:17
**/
@Service
public class AdminService {
@Autowired
private AdminMapper adminMapper;
public Admin findAdminByUsername(String username){
LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(Admin::getUsername,username);
queryWrapper.last("limit 1");
Admin admin = adminMapper.selectOne(queryWrapper);
return admin;
}
public List<Permission> fidnPermissionByAdminId(Long id) {
return adminMapper.findPermissionByAdminId(id);
}
}
package com.hmx.blog.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hmx.blog.admin.pojo.Admin;
import com.hmx.blog.admin.pojo.Permission;
import org.apache.ibatis.annotations.Select;
import java.util.List;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-19 12:17
**/
public interface AdminMapper extends BaseMapper<Admin> {
@Select("SELECT * FROM ms_permission where id in (select permission_id from ms_admin_permission where admin_id = #{adminId})")
List<Permission> findPermissionByAdminId(Long adminId);
}
package com.hmx.blog.admin.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.hmx.blog.admin.pojo.Permission;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-18 13:40
**/
public interface PermissionMapper extends BaseMapper<Permission> {
}
3.4 权限认证
package com.hmx.blog.admin.service;
import com.hmx.blog.admin.pojo.Admin;
import com.hmx.blog.admin.pojo.Permission;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Service;
import javax.servlet.http.HttpServletRequest;
import java.util.List;
/**
* @program: blog-parent
* @description:
* @author: hmx
* @create: 2021-08-19 13:08
**/
@Service
public class AuthService {
@Autowired
private AdminService adminService;
public boolean auth(HttpServletRequest request, Authentication authentication) {
//权限认证
//请求路径
String requestURI = request.getRequestURI();
Object principal = authentication.getPrincipal();
if (principal == null || "anonymousUser".equals(principal)){
//未登录
return false;
}
UserDetails userDetails = (UserDetails) principal;
String username = userDetails.getUsername();
Admin admin = adminService.findAdminByUsername(username);
if (admin == null) {
return false;
}
if(3 == admin.getId()) {
//超级管理员
return true;
}
Long id = admin.getId();
List<Permission> permissionList = this.adminService.fidnPermissionByAdminId(id);
requestURI = StringUtils.split(requestURI,'?')[0];
for (Permission permission : permissionList) {
if (requestURI.equals(permission.getPath())) {
return true;
}
}
return false;
}
}
<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis配置文件-->
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.mszlu.blog.admin.mapper.PermissionMapper">
<select id="findPermissionsByAdminId" parameterType="long" resultType="com.mszlu.blog.admin.pojo.Permission">
select * from ms_permission where id in (select permission_id from ms_admin_permission where admin_id=#{adminId})
</select>
</mapper>
4. 需要优化的地方
添加角色,用户拥有多个角色,一个角色拥有多个权限