controller
此处的 admin 是为了后面方便做拦截
import com.mszlu.blog.admin.model.params.PageParam; import com.mszlu.blog.admin.pojo.Permission; import com.mszlu.blog.admin.service.PermissionService; import com.mszlu.blog.admin.vo.Result; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; @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); } }
PageParam
import lombok.Data; @Data public class PageParam { private Integer currentPage; private Integer pageSize; private String queryString; }
Permission
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; }
Service
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.mszlu.blog.admin.mapper.PermissionMapper; import com.mszlu.blog.admin.model.params.PageParam; import com.mszlu.blog.admin.pojo.Permission; import com.mszlu.blog.admin.vo.PageResult; import com.mszlu.blog.admin.vo.Result; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @Service public class PermissionService { @Autowired private PermissionMapper permissionMapper; public Result listPermission(PageParam pageParam){ 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 = this.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); } }
Mapper
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mszlu.blog.admin.pojo.Permission; import java.util.List; public interface PermissionMapper extends BaseMapper<Permission> { }
配置一个返回类型
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); } }
PageResult
import lombok.Data; import java.util.List; @Data public class PageResult<T> { private List<T> list; private Long total; }
到此基本的权限系统已经配置完成了,接下来集成security来做登录及权限认证
Security集成
添加依赖
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
配置
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 myweb= new BCryptPasswordEncoder().encode("myweb"); System.out.println(myweb); } @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(); } }
登录认证
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; }
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.mszlu.blog.admin.mapper.AdminMapper; import com.mszlu.blog.admin.pojo.Admin; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.GrantedAuthority; 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.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.stereotype.Component; import java.util.ArrayList; @Component @Slf4j public class SecurityUserService implements UserDetailsService { @Autowired private AdminService adminService; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { log.info("username:{}",username); //当用户登录的时候,springSecurity 就会将请求 转发到此 //根据用户名 查找用户,不存在 抛出异常,存在 将用户名,密码,授权列表 组装成springSecurity的User对象 并返回 Admin adminUser = adminService.findAdminByUserName(username); if (adminUser == null){ throw new UsernameNotFoundException("用户名不存在"); } ArrayList<GrantedAuthority> authorities = new ArrayList<>(); UserDetails userDetails = new User(username,adminUser.getPassword(), authorities); //剩下的认证 就由框架帮我们完成 return userDetails; } public static void main(String[] args) { System.out.println(new BCryptPasswordEncoder().encode("123456")); } }
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.mszlu.blog.admin.mapper.AdminMapper; import com.mszlu.blog.admin.mapper.PermissionMapper; import com.mszlu.blog.admin.pojo.Admin; import com.mszlu.blog.admin.pojo.Permission; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.List; @Service public class AdminService { @Autowired private AdminMapper adminMapper; @Autowired private PermissionMapper permissionMapper; public Admin findAdminByUserName(String username){ LambdaQueryWrapper<Admin> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(Admin::getUsername,username).last("limit 1"); Admin adminUser = adminMapper.selectOne(queryWrapper); return adminUser; } public List<Permission> findPermissionsByAdminId(Long adminId){ return permissionMapper.findPermissionsByAdminId(adminId); } }
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mszlu.blog.admin.pojo.Admin; public interface AdminMapper extends BaseMapper<Admin> { }
import com.baomidou.mybatisplus.core.mapper.BaseMapper; import com.mszlu.blog.admin.pojo.Permission; import java.util.List; public interface PermissionMapper extends BaseMapper<Permission> { List<Permission> findPermissionsByAdminId(Long adminId); }
权限认证
import com.mszlu.blog.admin.mapper.AdminMapper; import com.mszlu.blog.admin.pojo.Admin; import com.mszlu.blog.admin.pojo.Permission; import lombok.extern.slf4j.Slf4j; 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.Collection; import java.util.List; @Service @Slf4j public class AuthService { @Autowired private AdminService adminService; public boolean auth(HttpServletRequest request, Authentication authentication){ String requestURI = request.getRequestURI(); log.info("request url:{}", requestURI); //true代表放行 false 代表拦截 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 (admin.getId() == 1){ //认为是超级管理员 return true; } List<Permission> permissions = adminService.findPermissionsByAdminId(admin.getId()); requestURI = StringUtils.split(requestURI,'?')[0]; for (Permission permission : permissions) { if (requestURI.equals(permission.getPath())){ log.info("权限通过"); return true; } } return false; } }
import org.springframework.security.core.GrantedAuthority; public class MySimpleGrantedAuthority implements GrantedAuthority { private String authority; private String path; public MySimpleGrantedAuthority(){} public MySimpleGrantedAuthority(String authority){ this.authority = authority; } public MySimpleGrantedAuthority(String authority,String path){ this.authority = authority; this.path = path; } @Override public String getAuthority() { return authority; } public String getPath() { return path; } }
<?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>