Initial commit
This commit is contained in:
parent
57e9cababa
commit
a04b3e49a0
@ -18,7 +18,7 @@ public enum ResultCodeEnum {
|
||||
FAIL(201, "失败"),
|
||||
SERVICE_ERROR(2012, "服务异常"),
|
||||
DATA_ERROR(204, "数据异常"),
|
||||
LOGIN_ERROR(205, "认证失败"),
|
||||
LOGIN_ERROR(204, "认证失败"),
|
||||
LOGIN_AUTH(208, "未登陆"),
|
||||
PERMISSION(209, "没有权限");
|
||||
|
||||
|
@ -32,6 +32,12 @@
|
||||
<groupId>com.github.xiaoymin</groupId>
|
||||
<artifactId>knife4j-spring-boot-starter</artifactId>
|
||||
</dependency>
|
||||
<!--引入security-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
|
||||
|
@ -1,6 +1,8 @@
|
||||
package com.atguigu.common.execption;
|
||||
package com.atguigu.common.config.execption;
|
||||
|
||||
import com.atguigu.common.result.Result;
|
||||
import com.atguigu.common.result.ResultCodeEnum;
|
||||
import org.springframework.security.access.AccessDeniedException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ -18,6 +20,12 @@ import org.springframework.web.bind.annotation.ResponseBody;
|
||||
@ControllerAdvice
|
||||
public class GlobalExceptionHandler {
|
||||
|
||||
/**
|
||||
* 全局异常处理,执行方法
|
||||
*
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(Exception.class)
|
||||
@ResponseBody
|
||||
public Result error(Exception e) {
|
||||
@ -25,6 +33,12 @@ public class GlobalExceptionHandler {
|
||||
return Result.fail();
|
||||
}
|
||||
|
||||
/**
|
||||
* 特定异常处理类
|
||||
*
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(ArithmeticException.class)
|
||||
@ResponseBody
|
||||
public Result error(ArithmeticException e) {
|
||||
@ -32,10 +46,28 @@ public class GlobalExceptionHandler {
|
||||
return Result.fail().message("执行了特定异常处理");
|
||||
}
|
||||
|
||||
/**
|
||||
* 自定义异常处理类
|
||||
*
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(GuiguException.class)
|
||||
@ResponseBody
|
||||
public Result error(GuiguException e) {
|
||||
e.printStackTrace();
|
||||
return Result.fail().message(e.getMsg()).code(e.getCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* spring security异常
|
||||
*
|
||||
* @param e
|
||||
* @return
|
||||
*/
|
||||
@ExceptionHandler(AccessDeniedException.class)
|
||||
@ResponseBody
|
||||
public Result error(AccessDeniedException e) throws AccessDeniedException {
|
||||
return Result.build(null, ResultCodeEnum.PERMISSION);
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
package com.atguigu.common.execption;
|
||||
package com.atguigu.common.config.execption;
|
||||
|
||||
import com.atguigu.common.result.ResultCodeEnum;
|
||||
import lombok.Data;
|
@ -38,5 +38,10 @@
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<!-- redis-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
|
@ -1,8 +1,22 @@
|
||||
package com.atguigu.security.config;
|
||||
|
||||
import com.atguigu.security.custom.CustomMd5PasswordEncoder;
|
||||
import com.atguigu.security.filter.TokenAuthenticationFilter;
|
||||
import com.atguigu.security.filter.TokenLoginFilter;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
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.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.config.http.SessionCreationPolicy;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
||||
|
||||
/**
|
||||
* ClassName: WebSecurityConfig
|
||||
@ -14,6 +28,66 @@ import org.springframework.security.config.annotation.web.configuration.WebSecur
|
||||
@Configuration
|
||||
//@EnableWebSecurity是开启SpringSecurity的默认行为
|
||||
@EnableWebSecurity
|
||||
//开启基于方法的安全认证机制,在web层的controller启用注解机制的安全确认
|
||||
@EnableGlobalMethodSecurity(prePostEnabled = true)
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
/**
|
||||
* 装载的是 org.springframework.security.core.userdetails.UserDetailsService;
|
||||
*/
|
||||
@Autowired
|
||||
private UserDetailsService userDetailsService;
|
||||
|
||||
@Autowired
|
||||
private CustomMd5PasswordEncoder customMd5PasswordEncoder;
|
||||
|
||||
@Autowired
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
@Bean
|
||||
@Override
|
||||
protected AuthenticationManager authenticationManager() throws Exception {
|
||||
return super.authenticationManager();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
// 这是配置的关键,决定哪些接口开启防护,哪些接口绕过防护
|
||||
http
|
||||
//关闭csrf跨站请求伪造
|
||||
.csrf().disable()
|
||||
// 开启跨域以便前端调用接口
|
||||
.cors().and()
|
||||
.authorizeRequests()
|
||||
// 指定某些接口不需要通过验证即可访问。登陆接口肯定是不需要认证的
|
||||
.antMatchers("/admin/system/index/login").permitAll()
|
||||
// 这里意思是其它所有接口需要认证才能访问
|
||||
.anyRequest().authenticated()
|
||||
.and()
|
||||
//TokenAuthenticationFilter放到UsernamePasswordAuthenticationFilter的前面,这样做就是为了除了登录的时候去查询数据库外,其他时候都用token进行认证。
|
||||
.addFilterBefore(new TokenAuthenticationFilter(redisTemplate), UsernamePasswordAuthenticationFilter.class)
|
||||
.addFilter(new TokenLoginFilter(authenticationManager(), redisTemplate));
|
||||
|
||||
//禁用session
|
||||
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
// 指定UserDetailService和加密器
|
||||
auth.userDetailsService(userDetailsService)
|
||||
.passwordEncoder(customMd5PasswordEncoder);
|
||||
}
|
||||
|
||||
/**
|
||||
* 配置哪些请求不拦截
|
||||
* 排除swagger相关请求
|
||||
*
|
||||
* @param web
|
||||
* @throws Exception
|
||||
*/
|
||||
@Override
|
||||
public void configure(WebSecurity web) throws Exception {
|
||||
web.ignoring().antMatchers("/favicon.ico", "/swagger-resources/**", "/webjars/**", "/v2/**", "/swagger-ui.html/**", "/doc.html");
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
* @author yovinchen
|
||||
* @Create 2023/6/10 23:28
|
||||
*/
|
||||
public interface UserDetailsService {
|
||||
public interface UserDetailsService extends org.springframework.security.core.userdetails.UserDetailsService {
|
||||
|
||||
/**
|
||||
* 根据用户名获取用户对象(获取不到直接抛异常)
|
||||
@ -19,5 +19,6 @@ public interface UserDetailsService {
|
||||
* @return
|
||||
* @throws UsernameNotFoundException
|
||||
*/
|
||||
@Override
|
||||
UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
|
||||
}
|
||||
|
@ -1,10 +1,13 @@
|
||||
package com.atguigu.security.filter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.atguigu.common.jwt.JwtHelper;
|
||||
import com.atguigu.common.result.Result;
|
||||
import com.atguigu.common.result.ResultCodeEnum;
|
||||
import com.atguigu.common.utils.ResponseUtil;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
@ -14,7 +17,9 @@ import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* ClassName: TokenAuthenticationFilter
|
||||
@ -26,8 +31,10 @@ import java.util.Collections;
|
||||
*/
|
||||
public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
|
||||
public TokenAuthenticationFilter() {
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
public TokenAuthenticationFilter(RedisTemplate redisTemplate) {
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -55,8 +62,22 @@ public class TokenAuthenticationFilter extends OncePerRequestFilter {
|
||||
if (!StringUtils.isEmpty(token)) {
|
||||
String useruame = JwtHelper.getUsername(token);
|
||||
logger.info("useruame:" + useruame);
|
||||
//认证成功
|
||||
if (!StringUtils.isEmpty(useruame)) {
|
||||
return new UsernamePasswordAuthenticationToken(useruame, null, Collections.emptyList());
|
||||
//通过username从reids中获取权限数据
|
||||
String authString = (String) redisTemplate.opsForValue().get(useruame);
|
||||
//将redis中获取的字符串权限数据转换为 ArrayList<SimpleGrantedAuthority>
|
||||
if (!StringUtils.isEmpty(authString)) {
|
||||
List<Map> mapList = JSON.parseArray(authString, Map.class);
|
||||
System.out.println(mapList);
|
||||
List<SimpleGrantedAuthority> authList = new ArrayList<>();
|
||||
for (Map map : mapList) {
|
||||
authList.add(new SimpleGrantedAuthority((String) map.get("authority")));
|
||||
}
|
||||
return new UsernamePasswordAuthenticationToken(useruame, null, authList);
|
||||
} else {
|
||||
return new UsernamePasswordAuthenticationToken(useruame, null, new ArrayList<>());
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
|
@ -1,5 +1,6 @@
|
||||
package com.atguigu.security.filter;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.atguigu.common.jwt.JwtHelper;
|
||||
import com.atguigu.common.result.Result;
|
||||
import com.atguigu.common.result.ResultCodeEnum;
|
||||
@ -7,6 +8,7 @@ import com.atguigu.common.utils.ResponseUtil;
|
||||
import com.atguigu.security.custom.CustomUser;
|
||||
import com.atguigu.vo.system.LoginVo;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
import org.springframework.security.authentication.AuthenticationManager;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
@ -31,13 +33,15 @@ import java.util.Map;
|
||||
* @Create 2023/6/10 23:37
|
||||
*/
|
||||
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||
private RedisTemplate redisTemplate;
|
||||
|
||||
// 构造方法
|
||||
public TokenLoginFilter(AuthenticationManager authenticationManager) {
|
||||
public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate) {
|
||||
this.setAuthenticationManager(authenticationManager);
|
||||
this.setPostOnly(false);
|
||||
//指定登录接口及提交方式,可以指定任意路径
|
||||
this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher("/admin/system/index/login", "POST"));
|
||||
this.redisTemplate = redisTemplate;
|
||||
}
|
||||
|
||||
// 登录认证过程
|
||||
@ -69,6 +73,8 @@ public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||
// 生成token
|
||||
String token = JwtHelper.createToken(customUser.getSysUser().getId(), customUser.getSysUser().getUsername());
|
||||
|
||||
//获取当前用户权限数据,放到Reids中,key: username value:权限数据
|
||||
redisTemplate.opsForValue().set(customUser.getUsername(), JSON.toJSONString(customUser.getAuthorities()));
|
||||
// 返回
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put("token", token);
|
||||
@ -81,7 +87,7 @@ public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
|
||||
AuthenticationException e) throws IOException, ServletException {
|
||||
|
||||
if (e.getCause() instanceof RuntimeException) {
|
||||
ResponseUtil.out(response, Result.build(null, ResultCodeEnum.DATA_ERROR));
|
||||
ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_ERROR));
|
||||
} else {
|
||||
ResponseUtil.out(response, Result.build(null, ResultCodeEnum.LOGIN_AUTH));
|
||||
}
|
||||
|
@ -2,7 +2,7 @@ package com.atguigu.auth.controller;
|
||||
|
||||
import com.atguigu.auth.service.SysMenuService;
|
||||
import com.atguigu.auth.service.SysUserService;
|
||||
import com.atguigu.common.execption.GuiguException;
|
||||
import com.atguigu.common.config.execption.GuiguException;
|
||||
import com.atguigu.common.jwt.JwtHelper;
|
||||
import com.atguigu.common.result.Result;
|
||||
import com.atguigu.common.utils.MD5;
|
||||
|
@ -11,6 +11,7 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import io.swagger.annotations.Api;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@ -63,11 +64,11 @@ public class SysRoleController {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@ApiOperation("查询所有角色")
|
||||
@GetMapping("findAll")
|
||||
public Result findAll() {
|
||||
return Result.ok(sysRoleService.list());
|
||||
}
|
||||
// @ApiOperation("查询所有角色")
|
||||
// @GetMapping("findAll")
|
||||
// public Result findAll() {
|
||||
// return Result.ok(sysRoleService.list());
|
||||
// }
|
||||
|
||||
/**
|
||||
* 条件分页查询
|
||||
@ -76,6 +77,7 @@ public class SysRoleController {
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.list')")
|
||||
@ApiOperation("条件分页查询")
|
||||
@GetMapping("{page}/{limit}")
|
||||
public Result pageQueryRole(@PathVariable Long page,
|
||||
@ -105,6 +107,7 @@ public class SysRoleController {
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.add')")
|
||||
@ApiOperation("添加角色")
|
||||
@PostMapping("save")
|
||||
public Result save(@RequestBody SysRole role) {
|
||||
@ -123,6 +126,7 @@ public class SysRoleController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.list')")
|
||||
@ApiOperation("根据id查询")
|
||||
@GetMapping("get/{id}")
|
||||
public Result get(@PathVariable Long id) {
|
||||
@ -136,6 +140,7 @@ public class SysRoleController {
|
||||
* @param role
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.update')")
|
||||
@ApiOperation("修改角色")
|
||||
@PutMapping("update")
|
||||
public Result update(@RequestBody SysRole role) {
|
||||
@ -154,6 +159,7 @@ public class SysRoleController {
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.remove')")
|
||||
@ApiOperation("根据id删除")
|
||||
@DeleteMapping("remove/{id}")
|
||||
public Result remove(@PathVariable Long id) {
|
||||
@ -172,6 +178,7 @@ public class SysRoleController {
|
||||
* @param idList
|
||||
* @return
|
||||
*/
|
||||
@PreAuthorize("hasAuthority('bnt.sysRole.remove')")
|
||||
@ApiOperation("批量删除")
|
||||
@DeleteMapping("batchRemove")
|
||||
public Result batchRemove(@RequestBody List<Long> idList) {
|
||||
|
@ -4,7 +4,7 @@ import com.atguigu.auth.mapper.SysMenuMapper;
|
||||
import com.atguigu.auth.service.SysMenuService;
|
||||
import com.atguigu.auth.service.SysRoleMenuService;
|
||||
import com.atguigu.auth.utils.MenuHelper;
|
||||
import com.atguigu.common.execption.GuiguException;
|
||||
import com.atguigu.common.config.execption.GuiguException;
|
||||
import com.atguigu.model.system.SysMenu;
|
||||
import com.atguigu.model.system.SysRoleMenu;
|
||||
import com.atguigu.vo.system.AssginMenuVo;
|
||||
|
@ -1,15 +1,18 @@
|
||||
package com.atguigu.auth.service.impl;
|
||||
|
||||
import com.atguigu.auth.service.SysMenuService;
|
||||
import com.atguigu.auth.service.SysUserService;
|
||||
import com.atguigu.model.system.SysUser;
|
||||
import com.atguigu.security.custom.CustomUser;
|
||||
import com.atguigu.security.custom.UserDetailsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* ClassName: UserDetailsServiceImpl
|
||||
@ -24,16 +27,26 @@ public class UserDetailsServiceImpl implements UserDetailsService {
|
||||
@Autowired
|
||||
private SysUserService sysUserService;
|
||||
|
||||
@Autowired
|
||||
private SysMenuService sysMenuService;
|
||||
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
SysUser sysUser = sysUserService.getByUsername(username);
|
||||
if(null == sysUser) {
|
||||
if (null == sysUser) {
|
||||
throw new UsernameNotFoundException("用户名不存在!");
|
||||
}
|
||||
|
||||
if(sysUser.getStatus() == 0) {
|
||||
if (sysUser.getStatus() == 0) {
|
||||
throw new RuntimeException("账号已停用");
|
||||
}
|
||||
return new CustomUser(sysUser, Collections.emptyList());
|
||||
//根据用户id查询用户操作权限
|
||||
List<String> userPermsList = sysMenuService.findUserPermsByUserId(sysUser.getId());
|
||||
//创建List集合,封装权限数据
|
||||
ArrayList<SimpleGrantedAuthority> authList = new ArrayList<>();
|
||||
for (String perm : userPermsList) {
|
||||
authList.add(new SimpleGrantedAuthority(perm.trim()));
|
||||
}
|
||||
return new CustomUser(sysUser, authList);
|
||||
}
|
||||
}
|
||||
|
@ -16,3 +16,15 @@ spring:
|
||||
jackson:
|
||||
date-format: yyyy-MM-dd HH:mm:ss
|
||||
time-zone: GMT+8
|
||||
redis:
|
||||
host: localhost
|
||||
port: 6379
|
||||
database: 0
|
||||
timeout: 1800000
|
||||
password:
|
||||
jedis:
|
||||
pool:
|
||||
max-active: 20 #最大连接数
|
||||
max-wait: -1 #最大阻塞等待时间(负数表示没限制)
|
||||
max-idle: 5 #最大空闲
|
||||
min-idle: 0 #最小空闲
|
||||
|
Loading…
Reference in New Issue
Block a user