代码实现
我们只需要根据用户id去查询到其所对应的权限信息即可。
【资料图】
所以我们可以先定义个mapper,其中提供一个方法可以根据userid查询权限信息。
package com.example.qinghuatokendemo.Mapper;import com.baomidou.mybatisplus.core.mapper.BaseMapper;import com.example.qinghuatokendemo.Domain.Menu;import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapperpublic interface MenuMapper extends BaseMapper
尤其是自定义方法,所以需要创建对应的mapper文件,定义对应的sql语句
在application.yml中配置mapperXML文件的位置
spring: datasource: url: jdbc:mysql://localhost:3306/springsecurity?characterEncoding=utf-8&serverTimezone=UTC username: root password: njzyb555 driver-class-name: com.mysql.cj.jdbc.Drivermybatis-plus: mapper-locations: classpath*:/mapper/**/*.xml
测试类
package com.example.qinghuatokendemo;import com.example.qinghuatokendemo.Domain.User;import com.example.qinghuatokendemo.Mapper.MenuMapper;import com.example.qinghuatokendemo.Mapper.UserMapper;import org.junit.jupiter.api.Test;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.test.context.SpringBootTest;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import java.util.List;@SpringBootTestpublic class MapperTest { @Autowired private UserMapper userMapper; @Autowired private MenuMapper menuMapper; @Autowired private PasswordEncoder passwordEncoder; @Test public void TestBCryptPasswordEncoder(){ //$2a$10$9CmQULPcw8prFL.gnmM/zO1bDtPtVNb4mTxNs2wHsm7xonGMCvT2C System.out.println(passwordEncoder. matches("1234", "$2a$10$eAQvguaa3mHMt7cUrXeQnu3vIw74tbNtthm/t1gH6IMrRihv1OpRu")); /*String encode = passwordEncoder.encode("1234"); System.out.println(encode);*/ } @Test public void testUser(){ List users = userMapper.selectList(null); System.out.println(users); } @Test public void testselectPermsByUserId(){ List list = menuMapper.selectPermsByUserId(1L); System.out.println(list); }} 我们还希望在认证失败或者是授权失败的情况下也能和我们的接口一样返回相同结构的json,这样可以让前端能对响应进行统一的处理。要实现这个功能我们需要知道SpringSecurity的异常处理机制。
在SpringSecurity中,如果我们在认证或者授权的过程中出现了异常会被ExceptionTranslationFilter捕获到。在ExceptionTranslationFilter中会去判断是认证失败还是授权失败出现的异常。
如果是认证过程中出现的异常会被封装成AuthenticationException然后调用AuthenticationEntryPoint对象的方法去进行异常处理。
如果是授权过程中出现的异常会被封装成AccessDeniedException然后调用AccessDeniedHandler对象的方法去进行异常处理。
所以如果我们需要自定义异常处理,我们只需要自定义AuthenticationEntryPoint和AccessDeniedHandler然后配置给SpringSecurity即可。
自定义实现类
package com.example.qinghuatokendemo.Handler;import com.alibaba.fastjson.JSON;import com.example.qinghuatokendemo.Domain.ResponseResult;import com.example.qinghuatokendemo.Utils.WebUtils;import org.springframework.http.HttpStatus;import org.springframework.security.core.AuthenticationException;import org.springframework.security.web.AuthenticationEntryPoint;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Componentpublic class AccessDeniedHandlerImpl implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException { ResponseResult result = new ResponseResult(HttpStatus.INTERNAL_SERVER_ERROR.value(),"用户认证失败请查询登录"); String json = JSON.toJSONString(request); //处理异常 WebUtils.renderString(response,json); }}package com.example.qinghuatokendemo.Handler;import com.alibaba.fastjson.JSON;import com.example.qinghuatokendemo.Domain.ResponseResult;import com.example.qinghuatokendemo.Utils.WebUtils;import org.springframework.http.HttpStatus;import org.springframework.security.access.AccessDeniedException;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.stereotype.Component;import javax.servlet.ServletException;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.io.IOException;@Componentpublic class AccessDeniedHandlerImpl implements AccessDeniedHandler { @Override public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException { ResponseResult result = new ResponseResult(HttpStatus.FORBIDDEN.value(), "权限不足"); String json = JSON.toJSONString(result); WebUtils.renderString(response,json); }}package com.example.qinghuatokendemo.Config;import com.example.qinghuatokendemo.Handler.AccessDeniedHandlerImpl;import com.example.qinghuatokendemo.filter.JwtAuthenticationTokenFilter;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;import org.springframework.security.authentication.AuthenticationManager;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.configuration.WebSecurityConfigurerAdapter;import org.springframework.security.config.http.SessionCreationPolicy;import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;import org.springframework.security.crypto.password.PasswordEncoder;import org.springframework.security.web.AuthenticationEntryPoint;import org.springframework.security.web.access.AccessDeniedHandler;import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;@Configuration@EnableGlobalMethodSecurity(prePostEnabled = true)public class SecurityConfig extends WebSecurityConfigurerAdapter { @Bean public PasswordEncoder passwordEncoder(){ return new BCryptPasswordEncoder(); } @Autowired JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter; @Autowired private AuthenticationEntryPoint authenticationEntryPoint; @Autowired private AccessDeniedHandler accessDeniedHandler; @Override protected 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 .csrf().disable() .sessionManagement() .sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .authorizeRequests() .antMatchers("/hello").permitAll() .antMatchers("/user/login").anonymous() .anyRequest().authenticated(); //把token校验过滤器添加到过滤器链中 http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class); //配置异常处理器 http.exceptionHandling() //认证失败处理器 .authenticationEntryPoint(authenticationEntryPoint).accessDeniedHandler(accessDeniedHandler); } @Bean @Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }}
标签: