农产品的网站建设与维护论文,网站建设教程流程图,python做网站步骤,app开发步骤1 Spring Security介绍 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员#xff0c;因此它伴随着整个Spring生态系统不断修正、升级#xff0c;在spring boot项目中加入springsecurity更是…1 Spring Security介绍 Spring Security是一个能够为基于Spring的企业应用系统提供声明式的安全访问控制解决方案的安全框架。由于它是Spring生态系统中的一员因此它伴随着整个Spring生态系统不断修正、升级在spring boot项目中加入springsecurity更是十分简单使用Spring Security 减少了为企业系统安全控制编写大量重复代码的工作。原名叫acegi在2007年底才更名为 Spring Security
2 认证流程 Spring Security 功能的实现主要是靠一系列的过滤器链相互配合来完成的。以下是项目启动时打印的默认安全过滤器链集成5.2.0
[org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter5054e546,org.springframework.security.web.context.SecurityContextPersistenceFilter7b0c69a6,org.springframework.security.web.header.HeaderWriterFilter4fefa770,org.springframework.security.web.csrf.CsrfFilter6346aba8,org.springframework.security.web.authentication.logout.LogoutFilter677ac054,org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter51430781,org.springframework.security.web.savedrequest.RequestCacheAwareFilter4203d678,org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter625e20e6,org.springframework.security.web.authentication.AnonymousAuthenticationFilter19628fc2,org.springframework.security.web.session.SessionManagementFilter471f8a70,org.springframework.security.web.access.ExceptionTranslationFilter3e1eb569,org.springframework.security.web.access.intercept.FilterSecurityInterceptor3089ab62
]WebAsyncManagerIntegrationFilterSecurityContextPersistenceFilterHeaderWriterFilterCsrfFilterLogoutFilterUsernamePasswordAuthenticationFilterRequestCacheAwareFilterSecurityContextHolderAwareRequestFilterAnonymousAuthenticationFilterSessionManagementFilterExceptionTranslationFilterFilterSecurityInterceptor
详细解读可以参考Spring Security 核心过滤器链分析_defaultsecurityfilterchain-CSDN博客
在解析前先说说两个至关重要的类OncePerRequestFilter和GenericFilterBean在过滤器链的过滤器中或多或少间接或直接继承到
OncePerRequestFilter顾名思义能够确保在一次请求只通过一次filter而不需要重复执行。 GenericFilterBean是javax.servlet.Filter接口的一个基本的实现类 GenericFilterBean将web.xml中filter标签中的配置参数-init-param项作为bean的属性 GenericFilterBean可以简单地成为任何类型的filter的父类 GenericFilterBean的子类可以自定义一些自己需要的属性 GenericFilterBean将实际的过滤工作留给他的子类来完成这就导致了他的子类不得不实现doFilter方法 GenericFilterBean不依赖于Spring的ApplicationContextFilters通常不会直接读取他们的容器信息ApplicationContext concept而是通过访问spring容器Spring root application context中的service beans来获取通常是通过调用filter里面的getServletContext() 方法来获取
3 SpringSecurity的使用用户认证加注册
步骤一pom.xml中导入依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-web/artifactId
/dependency
!-- jwt依赖--
dependencygroupIdcom.auth0/groupIdartifactIdjava-jwt/artifactIdversion3.10.3/version
/dependency
!--redis依赖--
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId
/dependency
!--mybatisplus依赖--
dependencygroupIdcom.baomidou/groupIdartifactIdmybatis-plus-boot-starter/artifactIdversion3.5.1/version
/dependency
!--mysql依赖--
dependencygroupIdmysql/groupIdartifactIdmysql-connector-java/artifactIdversion8.0.29/version
/dependency
dependencygroupIdorg.projectlombok/groupIdartifactIdlombok/artifactIdoptionaltrue/optional
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-test/artifactIdscopetest/scope
/dependency
dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-test/artifactIdscopetest/scope
/dependency
当导入这个依赖后在访问任何接口的时候都会被过滤器拦截它会先跳到Spring Security默认的登录页面去。如下图所示 需要登录后才来访问请求的接口用户名:user密码会自动生成在idea控制台上面可以找到
当然这个页面主要用于测试用的我们实际开发是不会用这个页面的。
步骤二 定义PasswordEncoder密码解析器解释
Spring Security官方推荐的密码解析器。可以通过strength控制加密强度默认10。
Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {Beanpublic PasswordEncoder passwordEncoder(){return new BCryptPasswordEncoder();}
}
BCryptPasswordEncoder()提供了有参构造器可以传入一个4到31的整数设置值越大密码编码越安全但是性能越越低因此这个值正常不要设置很大若不设置的话默认为10。
当然有可以使用自定义的密码解析器解释,但是一般很少自己去写除非特殊要求。定义格式如下
public class MyPasswordEncoder implements PasswordEncoder {Overridepublic String encode(CharSequence rawPassword) {System.out.println(自定义密码解析器 - encode方法执行);return rawPassword.toString();}Overridepublic boolean matches(CharSequence rawPassword, String encodedPassword) {System.out.println(自定义密码解析器 - matches方法执行);// 先使用encode方法用相同的加密策略加密明文再对比密文。return encode(rawPassword).equals(encodedPassword);}Overridepublic boolean upgradeEncoding(String encodedPassword) {return PasswordEncoder.super.upgradeEncoding(encodedPassword);}
}Configuration
public class MySecurityConfiguration extends WebSecurityConfigurerAdapter {Beanpublic PasswordEncoder passwordEncoder(){
//自定义密码解析器return new MyPasswordEncoder();}
}
步骤三实现UserDetailsService接口
Component
public class MyUserDetailsServiceImpl implements UserDetailsService {Autowiredprivate UserMapper userMapper;Overridepublic UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {System.out.println(自定义登录服务 - loadUserByUsername方法执行);LambdaQueryWrapperUser lqw new LambdaQueryWrapper();lqw.eq(User::getUsername, username);// 根据用户名查询用户User user userMapper.selectOne(lqw);// 判断用户名是否存在if(user null){System.out.println(用户名 username 不存在);// 用户名不存在throw new UsernameNotFoundException(用户名或密码错误);}LoginUser loginUser new LoginUser();loginUser.setUser(user);return loginUser;}} loadUserByUsername需要返回UserDetails对象而UserDetails其实是一个接口因此我们可以去实现这个接口。 loadUserByUsername中要是出现异常会自动执行security的**/err接口
Data
NoArgsConstructor
AllArgsConstructor
// 解决后续redis读取数据时反序列化报错
JsonIgnoreProperties(ignoreUnknown true)
public class LoginUser implements UserDetails {//这是一个实体类需要自己提前定义private User user;Overridepublic Collection? extends GrantedAuthority getAuthorities() {return null;}/*** 框架中会自动调用获取用户名和密码的操作所以返回值要重写一下* return*/Overridepublic String getPassword() {return user.getPassword();}Overridepublic String getUsername() {return user.getUsername();}/*** 布尔值记得改为True否则可能无法访问*/Overridepublic boolean isAccountNonExpired() {return true;}Overridepublic boolean isAccountNonLocked() {return true;}Overridepublic boolean isCredentialsNonExpired() {return true;}Overridepublic boolean isEnabled() {return true;}
}
步骤四取消security的默认页面
下列代码添加到步骤二的类中。 Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests()// 对于登录接口 允许匿名访问.antMatchers(/user/login).anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class);}OverrideBeanpublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}
步骤五:自定义登录请求
RestController
RequestMapping(/user)
public class UserController {Autowiredprivate IUserService userService;//登录PostMapping(/login)public AjaxResult login(User user){String resultuserService.login(user);return AjaxResult.success(result);}
} public interface IUserService extends IServiceUser {
//登录String login(User user);
}package com.mashang.service.impl;import com.mashang.config.RedisUtil;
import com.mashang.entity.LoginUser;
import com.mashang.entity.User;
import com.mashang.mapper.UserMapper;
import com.mashang.service.IUserService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.mashang.utils.JWTUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;import java.util.Objects;
import java.util.concurrent.TimeUnit;/*** p* 服务实现类* /p** author author* since 2024-09-09*/
Service
Slf4j
public class UserServiceImpl extends ServiceImplUserMapper, User implements IUserService {Autowiredprivate AuthenticationManager authenticationManager;Autowiredprivate RedisUtil redisUtil;Override
/*** 用户登录方法* 该方法主要用于用户登录通过验证用户的用户名和密码来生成并返回一个JWTJson Web Token** param user 用户对象包含用户名和密码* return 返回一个JWT用于后续的用户身份验证* throws RuntimeException 如果用户认证失败则抛出运行时异常*/
public String login(User user) {// 创建一个包含用户名和密码的认证令牌UsernamePasswordAuthenticationToken token new UsernamePasswordAuthenticationToken(user.getUsername(), user.getPassword());// 使用认证管理器进行用户认证最终会调用到 loadUserByUsername方法返回认证的信息Authentication authenticate authenticationManager.authenticate(token);// 检查认证结果如果为空则记录错误并抛出异常if (Objects.isNull(authenticate)) {log.error(认证失败);throw new RuntimeException(认证失败);}// 从认证对象中获取登录用户信息LoginUser loginUser (LoginUser) authenticate.getPrincipal();// 为用户生成JWTString jwt JWTUtil.createToken(loginUser.getUser());// 将用户信息存储到Redis中设置过期时间redisUtil.setCacheObject(user: loginUser.getUser().getId(), loginUser, 30, TimeUnit.MINUTES);// 返回生成的JWTreturn jwt;
}}
步骤六导入工具类
1Redis序列化
package com.mashang.config;import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;Configuration
public class RedisConfig {// 定义了一个RedisTemplateBeanSuppressWarnings(all)public RedisTemplateString, Object redisTemplate(RedisConnectionFactory redisConnectionFactory) {// RedisTemplate 为了自己方便一般直接使用String,ObjectRedisTemplateString, Object template new RedisTemplate();template.setConnectionFactory(redisConnectionFactory);// 序列化配置Jackson2JsonRedisSerializerObject jackson2JsonRedisSerializer new Jackson2JsonRedisSerializerObject(Object.class);ObjectMapper om new ObjectMapper();// 设置可见度om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 启动默认的类型om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);// 序列化类对象映射设置jackson2JsonRedisSerializer.setObjectMapper(om);// String的序列化StringRedisSerializer stringRedisSerializer new StringRedisSerializer();// key采用String的序列化方式template.setKeySerializer(stringRedisSerializer);// hash的key采用String的序列化template.setHashKeySerializer(stringRedisSerializer);// value采用jackson的序列化template.setValueSerializer(jackson2JsonRedisSerializer);// hash的value采用jackson的序列化template.setHashValueSerializer(jackson2JsonRedisSerializer);return template;}
}
2 Redis工具类
package com.mashang.config;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundSetOperations;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;import java.util.*;
import java.util.concurrent.TimeUnit;/*** spring redis 工具类** author ruoyi**/
SuppressWarnings(value {unchecked, rawtypes})
Component
public class RedisUtil {Autowiredpublic RedisTemplate redisTemplate;/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值*/public T void setCacheObject(final String key, final T value) {redisTemplate.opsForValue().set(key, value);}/*** 缓存基本的对象Integer、String、实体类等** param key 缓存的键值* param value 缓存的值* param timeout 时间* param timeUnit 时间颗粒度*/public T void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit) {redisTemplate.opsForValue().set(key, value, timeout, timeUnit);}/*** 设置有效时间** param key Redis键* param timeout 超时时间* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout) {return expire(key, timeout, TimeUnit.SECONDS);}/*** 设置有效时间** param key Redis键* param timeout 超时时间* param unit 时间单位* return true设置成功false设置失败*/public boolean expire(final String key, final long timeout, final TimeUnit unit) {return redisTemplate.expire(key, timeout, unit);}/*** 获得缓存的基本对象。** param key 缓存键值* return 缓存键值对应的数据*/public T T getCacheObject(final String key) {ValueOperationsString, T operation redisTemplate.opsForValue();return operation.get(key);}/*** 删除单个对象** param key*/public boolean deleteObject(final String key) {return redisTemplate.delete(key);}/*** 删除集合对象** param collection 多个对象* return*/public long deleteObject(final Collection collection) {return redisTemplate.delete(collection);}/*** 缓存List数据** param key 缓存的键值* param dataList 待缓存的List数据* return 缓存的对象*/public T long setCacheList(final String key, final ListT dataList) {Long count redisTemplate.opsForList().rightPushAll(key, dataList);return count null ? 0 : count;}/*** 获得缓存的list对象** param key 缓存的键值* return 缓存键值对应的数据*/public T ListT getCacheList(final String key) {return redisTemplate.opsForList().range(key, 0, -1);}/*** 缓存Set** param key 缓存键值* param dataSet 缓存的数据* return 缓存数据的对象*/public T BoundSetOperationsString, T setCacheSet(final String key, final SetT dataSet) {BoundSetOperationsString, T setOperation redisTemplate.boundSetOps(key);IteratorT it dataSet.iterator();while (it.hasNext()) {setOperation.add(it.next());}return setOperation;}/*** 获得缓存的set** param key* return*/public T SetT getCacheSet(final String key) {return redisTemplate.opsForSet().members(key);}/*** 缓存Map** param key* param dataMap*/public T void setCacheMap(final String key, final MapString, T dataMap) {if (dataMap ! null) {redisTemplate.opsForHash().putAll(key, dataMap);}}/*** 获得缓存的Map** param key* return*/public T MapString, T getCacheMap(final String key) {return redisTemplate.opsForHash().entries(key);}/*** 往Hash中存入数据** param key Redis键* param hKey Hash键* param value 值*/public T void setCacheMapValue(final String key, final String hKey, final T value) {redisTemplate.opsForHash().put(key, hKey, value);}/*** 获取Hash中的数据** param key Redis键* param hKey Hash键* return Hash中的对象*/public T T getCacheMapValue(final String key, final String hKey) {HashOperationsString, String, T opsForHash redisTemplate.opsForHash();return opsForHash.get(key, hKey);}/*** 删除Hash中的数据** param key* param hKey*/public void delCacheMapValue(final String key, final String hKey) {HashOperations hashOperations redisTemplate.opsForHash();hashOperations.delete(key, hKey);}/*** 获取多个Hash中的数据** param key Redis键* param hKeys Hash键集合* return Hash对象集合*/public T ListT getMultiCacheMapValue(final String key, final CollectionObject hKeys) {return redisTemplate.opsForHash().multiGet(key, hKeys);}/*** 获得缓存的基本对象列表** param pattern 字符串前缀* return 对象列表*/public CollectionString keys(final String pattern) {return redisTemplate.keys(pattern);}
}
3 JWT工具类
package com.mashang.utils;import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.mashang.entity.User;
import org.springframework.stereotype.Component;import java.util.Calendar;
Component
public class JWTUtil {// 加密的秘钥封装一下private static final String SECRET jhkasdfghadsfgsdafkl;// id字段private static final String ID_FIELD userID;// token的有效时间 30 天private static final Integer TIME_OUT_DAY 30;/*** 创建token** param user 登陆的用户* return 返回Token字符串*/public static String createToken(User user) {// 获取日历对象实例Calendar calendar Calendar.getInstance();// 在当前日期加上 TIME_OUT_DAY 的时间用于设置过期时间calendar.add(Calendar.DATE, TIME_OUT_DAY);System.out.println(user.getId());// 创建jwtreturn JWT.create()// 可以在token中设置数据,设置一个userId为用户的id// 后续可以直接在token中获取id.withClaim(ID_FIELD, user.getId())// 设置桂平群殴瑟吉欧靠门.withExpiresAt(calendar.getTime())// Algorithm.HMAC256(SECRET) 使用HMAC256的加密方式// secret 指的是秘钥在这个秘钥的基础上进行加密加大破解的难度这个秘钥爱写什么写什么.sign(Algorithm.HMAC256(SECRET));}/*** 验证JWT返回为false的时候表示验证失败** param token token字符串* return 返回boolean 表示是否登录成功*/public static boolean verifyToken(String token) {try {// 验证JWT验证不通过会报错JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token);return true;} catch (Exception e) {return false;}}/*** 获取用户id返回值是0表示没有找到id** param token token 字符串* return 返回对应的用户id如果为0则表示没有用户*/public static Long getUserId(String token) {try {// 获取id没有id则会报错return JWT.require(Algorithm.HMAC256(SECRET)).build().verify(token).getClaim(ID_FIELD).asLong();} catch (Exception e) {// 如果报错就返回null表示没有找到对应的用户return 0L;}}
} 4 数据返回
package com.mashang.yanzhengma;import java.util.HashMap;
import java.util.Objects;import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;/*** 操作消息提醒* * author ruoyi*/
ApiModel(操作消息提醒)
public class AjaxResult extends HashMapString, Object
{private static final long serialVersionUID 1L;/** 状态码 */ApiModelProperty(状态码)public static final String CODE_TAG code;/** 返回内容 */ApiModelProperty(返回内容)public static final String MSG_TAG msg;/** 数据对象 */ApiModelProperty(数据对象)public static final String DATA_TAG data;/*** 初始化一个新创建的 AjaxResult 对象使其表示一个空消息。*/public AjaxResult(){}/*** 初始化一个新创建的 AjaxResult 对象* * param code 状态码* param msg 返回内容*/public AjaxResult(int code, String msg){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);}/*** 初始化一个新创建的 AjaxResult 对象* * param code 状态码* param msg 返回内容* param data 数据对象*/public AjaxResult(int code, String msg, Object data){super.put(CODE_TAG, code);super.put(MSG_TAG, msg);if (StringUtils.isNotNull(data)){super.put(DATA_TAG, data);}}/*** 返回成功消息* * return 成功消息*/public static AjaxResult success(){return AjaxResult.success(操作成功);}/*** 返回成功数据* * return 成功消息*/public static AjaxResult success(Object data){return AjaxResult.success(操作成功, data);}/*** 返回成功消息* * param msg 返回内容* return 成功消息*/public static AjaxResult success(String msg){return AjaxResult.success(msg, null);}/*** 返回成功消息* * param msg 返回内容* param data 数据对象* return 成功消息*/public static AjaxResult success(String msg, Object data){return new AjaxResult(HttpStatus.SUCCESS, msg, data);}/*** 返回警告消息** param msg 返回内容* return 警告消息*/public static AjaxResult warn(String msg){return AjaxResult.warn(msg, null);}/*** 返回警告消息** param msg 返回内容* param data 数据对象* return 警告消息*/public static AjaxResult warn(String msg, Object data){return new AjaxResult(HttpStatus.WARN, msg, data);}/*** 返回错误消息* * return 错误消息*/public static AjaxResult error(){return AjaxResult.error(操作失败);}/*** 返回错误消息* * param msg 返回内容* return 错误消息*/public static AjaxResult error(String msg){return AjaxResult.error(msg, null);}/*** 返回错误消息* * param msg 返回内容* param data 数据对象* return 错误消息*/public static AjaxResult error(String msg, Object data){return new AjaxResult(HttpStatus.ERROR, msg, data);}public static AjaxResult error(int code,String msg, Object data){return new AjaxResult(code, msg, data);}/*** 返回错误消息* * param code 状态码* param msg 返回内容* return 错误消息*/public static AjaxResult error(int code, String msg){return new AjaxResult(code, msg, null);}/*** 是否为成功消息** return 结果*/public boolean isSuccess(){return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));}/*** 是否为警告消息** return 结果*/public boolean isWarn(){return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));}/*** 是否为错误消息** return 结果*/public boolean isError(){return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));}/*** 方便链式调用** param key 键* param value 值* return 数据对象*/Overridepublic AjaxResult put(String key, Object value){super.put(key, value);return this;}
}5 JWTFilter过滤器
Component
public class JWTFilter extends OncePerRequestFilter {Autowiredprotected RedisUtil redisUtil;Autowiredprotected RedisTemplate redisTemplate;Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token request.getHeader(token);if (token null ||!JWTUtil.verifyToken(token)) {
//后面还有很多过滤器会有过滤器进行拦截的 filterChain.doFilter(request, response);return;}LoginUser loginUser (LoginUser)redisUtil.getCacheObject(user: JWTUtil.getUserId(token));if (loginUser null){response.setContentType(application/json;charsetUTF-8);response.getWriter().write(JSONUtil.toJsonStr(AjaxResult.error(401,请登录,)));return;}else {//更新redis中保存的token的过期时间redisTemplate.expire(user: JWTUtil.getUserId(token), 30, TimeUnit.MINUTES);}
//让后面过滤器不再拦截UsernamePasswordAuthenticationToken authenticationToken new UsernamePasswordAuthenticationToken(loginUser, null, null);SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request, response);}}步骤七 注册用户 PostMapping(/register)public String register(User user){BCryptPasswordEncoder encodernew BCryptPasswordEncoder();user.setPassword(encoder.encode(user.getPassword()));userService.save(user);return 注册成功;}
4 授权
授权需要在数据库创建五张表分别是用户表、角色表、权限表用户角色关联表、角色权限关联表。建表语句在后面.
步骤一启动类开启配置
EnableGlobalMethodSecurity(prePostEnabled true)
步骤二自定义鉴权方法
Component(ss)
public class MyExpressionUtil {public boolean hasPermission(String permission) {//未来可以改为数据库查询当返回true代表可以访问false不能访问接口return true;}
}
步骤三在接口上添加注解
GetMapping(/t1)PreAuthorize(ss.hasPermission(t1))public String getUserInfo(){return hello;}
PreAuthorize(ss.hasPermission(t1))解释接口上加上这个注解首先会去容器找名为ss的类然后找到ss类的hasPermission方法会将t1值作为参数传给hasPermission方法意思permission现在就保存着t1执行完这个方法会返回布尔值当返回True就表示可以访问该接口。hasPermission方法内的逻辑最终可以改为数据库查询。 数据库
CREATE TABLE tb_permission (id int NOT NULL AUTO_INCREMENT,name varchar(32) DEFAULT NULL COMMENT 权限名称,url varchar(255) DEFAULT NULL COMMENT 请求地址,parent_id int DEFAULT NULL COMMENT 父权限主键,type varchar(24) DEFAULT NULL COMMENT 权限类型 M - 菜单 A - 子菜单 U - 普通请求,permit varchar(128) DEFAULT NULL COMMENT 权限字符串描述如user:list 用户查看权限 user 用户权限 user:insert 用户新增权限 等,remark text COMMENT 描述,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT14 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;CREATE TABLE tb_role (id int NOT NULL AUTO_INCREMENT,name varchar(32) DEFAULT NULL COMMENT 角色名称,remark text COMMENT 角色描述,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT3 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;CREATE TABLE tb_role_permission (role_id int DEFAULT NULL COMMENT 角色外键,permission_id int DEFAULT NULL COMMENT 权限外键
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;CREATE TABLE tb_user (id int NOT NULL AUTO_INCREMENT,name varchar(32) DEFAULT NULL COMMENT 姓名,username varchar(32) DEFAULT NULL COMMENT 用户名,password varchar(128) DEFAULT NULL COMMENT 密码,remark text COMMENT 描述,PRIMARY KEY (id)
) ENGINEInnoDB AUTO_INCREMENT3 DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;CREATE TABLE tb_user_role (user_id int DEFAULT NULL COMMENT 用户外键,role_id int DEFAULT NULL COMMENT 角色外键
) ENGINEInnoDB DEFAULT CHARSETutf8mb4 COLLATEutf8mb4_0900_ai_ci;