springboot
一个简单的security安全登录示例
- 配置环境
- 添加pom依赖坐标
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version></parent><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</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-security</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>
- application.yml文件配置
server:port: 9999 spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootmain:allow-bean-definition-overriding: trueredis:port: 6379host: 127.0.0.1 logging:level:root: INFOorg.springframework.web.servlet.DispatcherServlet: DEBUGorg.springframework.cloud.sleuth: DEBUG
- 数据库就一张用户表(简单登录:用户表)
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- Table structure for tb_user -- ---------------------------- DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` (`id` int(11) NOT NULL,`account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`role` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ---------------------------- -- Records of tb_user -- ---------------------------- INSERT INTO `tb_user` VALUES (1, '123456', 'admin', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', 'test'); INSERT INTO `tb_user` VALUES (2, '789456', 'zhangsan', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', NULL);SET FOREIGN_KEY_CHECKS = 1;
- 编写统一返回类
@Data @Accessors(chain = true) public class R {//成功状态位private Boolean success;//响应消息private String message;//响应码private Integer code;//响应数据private Object data;private static final String DEFAULT_SUCCESS_MESSAGE = "OK";private static final Integer DEFAULT_SUCCESS_CODE = 20000;private static final String DEFAULT_FALL_MESSAGE = "ERROR";private static final Integer DEFAULT_FALL_CODE = 50000;private R(Boolean success, String message, Integer code, Object data) {this.success = success;this.message = message;this.code = code;this.data = data;}public static R success(){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(String message){R r = new R(true,message,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(Object data){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,data);return r;}public static R success(String message,Object data){R r = new R(true,message,DEFAULT_SUCCESS_CODE,data);return r;}public static R fail(){R r = new R(false,DEFAULT_FALL_MESSAGE,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message){R r = new R(false,message,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message,Integer code){R r = new R(false,message,code,null);return r;} }
- redis配置
@Configuration public class RedisConfig {/*** retemplate相关配置* @param factory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jacksonSeial.setObjectMapper(om);// 值采用json序列化template.setValueSerializer(jacksonSeial);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());// 设置hash key 和value序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jacksonSeial);template.afterPropertiesSet();return template;}}
- 添加pom依赖坐标
- 创建实体类,实现接口UserDetails,实现获取权限方法
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class UserBean implements UserDetails {private String account;private String username;private String password;private String role;@JSONField(serialize = false)private List<SimpleGrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if (authorities != null) {return authorities;}authorities = new ArrayList<>();if(null!=role){SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role);authorities.add(simpleGrantedAuthority);}return authorities;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;} }
- 创建mapper接口,编写sql语句
@Mapper public interface UserBeanMapper {//根据账号查询用户信息@Select("select * from tb_user where account=#{account}")UserBean findUserById(@Param("account")String account); }
- 创建service层登录接口
public interface UserBeanService {R login(String account,String password); }
- 实现service层接口
@Service public class UserServiceImpl implements UserBeanService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overridepublic R login(String account, String password) { //创建用户身份验证UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(account, password);Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);if(null==authenticate){return R.fail("账户名或密码错误");} //以hash方式存储redis中redisTemplate.boundHashOps(account).put(account, JSON.toJSONString(authenticate.getPrincipal())); //设置redis过期时间redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);return R.success(JwtUtil.createJWT(account));} }
- 创建controller层
@RestController public class UserBeanController {@Autowiredprivate UserBeanService userBeanService;//登录@PostMapping("/login")public R login(@RequestParam("account") String account, @RequestParam("password") String password){return userBeanService.login(account,password);}//权限测试@GetMapping("/test")@PreAuthorize("hasAuthority('test')")public R test(){return R.success("这是一条提示消息","test");} }
security相关代码配置
- 这里使用jwt令牌,创建jwt工具类
/*** JWT工具类*/ public class JwtUtil {//有效期为public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时//设置秘钥明文public static final String JWT_KEY = "mingwen";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间return builder.compact();}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @param ttlMillis token超时时间* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid) //唯一的ID.setSubject(subject) // 主题 可以是JSON数据.setIssuer("sanyue") // 签发者.setIssuedAt(now) // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/*** 创建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}/*** 生成加密后的秘钥 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}
- 创建jwt过滤器
@Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("token");if (!StringUtils.hasText(token)) {filterChain.doFilter(request, response);return;}String account = null; //校验tokentry {Claims claims = JwtUtil.parseJWT(token);account = claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("非法token");} //判断redis该用户是否超时存在if(Boolean.FALSE.equals(redisTemplate.boundHashOps(account).hasKey(account))){throw new RuntimeException("用户登录超时请重新登录");} //取出该用户相关信息 同时延长redis存储时间String redisUserObj = redisTemplate.boundHashOps(account).get(account).toString();redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);UserBean userBean = JSON.parseObject(redisUserObj, UserBean.class); //将用户信息,及权限交给securityUsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userBean,null,userBean.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request, response);} }
- 继承security适配器,配置security
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//密码校验规则@Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//把token校验过滤器添加到过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/login/**","/logout/**");} }
- 实现接口UserDetailsService 并实现方法,走我们自己的业务逻辑
@Service public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserBeanMapper userBeanMapper;@Overridepublic UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {return userBeanMapper.findUserById(account);} }
启动项目
- 启动类
@SpringBootApplication public class SecurityApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(SecurityApplication.class, args);BCryptPasswordEncoder bean = run.getBean(BCryptPasswordEncoder.class);System.out.println(bean.encode("123456"));} }
- 测试数据
- admin登录
- admin访问对应权限方法
- zhangsan登录
- zhangsan访问权限方法
写的不怎么样,希望对大家有用,希望大家多多指点~~~
springboot
一个简单的security安全登录示例
- 配置环境
- 添加pom依赖坐标
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.1.6.RELEASE</version></parent><dependencies><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</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-security</artifactId></dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId></dependency><dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.2.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency><dependency><groupId>io.jsonwebtoken</groupId><artifactId>jjwt</artifactId><version>0.9.0</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>fastjson</artifactId><version>1.2.76</version></dependency></dependencies>
- application.yml文件配置
server:port: 9999 spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/db_security?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghaiusername: rootpassword: rootmain:allow-bean-definition-overriding: trueredis:port: 6379host: 127.0.0.1 logging:level:root: INFOorg.springframework.web.servlet.DispatcherServlet: DEBUGorg.springframework.cloud.sleuth: DEBUG
- 数据库就一张用户表(简单登录:用户表)
SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;-- ---------------------------- -- Table structure for tb_user -- ---------------------------- DROP TABLE IF EXISTS `tb_user`; CREATE TABLE `tb_user` (`id` int(11) NOT NULL,`account` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`password` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,`role` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NULL DEFAULT NULL,PRIMARY KEY (`id`) USING BTREE ) ENGINE = InnoDB CHARACTER SET = utf8 COLLATE = utf8_general_ci ROW_FORMAT = Compact;-- ---------------------------- -- Records of tb_user -- ---------------------------- INSERT INTO `tb_user` VALUES (1, '123456', 'admin', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', 'test'); INSERT INTO `tb_user` VALUES (2, '789456', 'zhangsan', '$2a$10$gGKeupjLdvbaoYdAlz1MfuiT/4llYvGFU2QeQ..CQIhCXyqXekn5.', NULL);SET FOREIGN_KEY_CHECKS = 1;
- 编写统一返回类
@Data @Accessors(chain = true) public class R {//成功状态位private Boolean success;//响应消息private String message;//响应码private Integer code;//响应数据private Object data;private static final String DEFAULT_SUCCESS_MESSAGE = "OK";private static final Integer DEFAULT_SUCCESS_CODE = 20000;private static final String DEFAULT_FALL_MESSAGE = "ERROR";private static final Integer DEFAULT_FALL_CODE = 50000;private R(Boolean success, String message, Integer code, Object data) {this.success = success;this.message = message;this.code = code;this.data = data;}public static R success(){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(String message){R r = new R(true,message,DEFAULT_SUCCESS_CODE,null);return r;}public static R success(Object data){R r = new R(true,DEFAULT_SUCCESS_MESSAGE,DEFAULT_SUCCESS_CODE,data);return r;}public static R success(String message,Object data){R r = new R(true,message,DEFAULT_SUCCESS_CODE,data);return r;}public static R fail(){R r = new R(false,DEFAULT_FALL_MESSAGE,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message){R r = new R(false,message,DEFAULT_FALL_CODE,null);return r;}public static R fail(String message,Integer code){R r = new R(false,message,code,null);return r;} }
- redis配置
@Configuration public class RedisConfig {/*** retemplate相关配置* @param factory* @return*/@Beanpublic RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {RedisTemplate<String, Object> template = new RedisTemplate<>();// 配置连接工厂template.setConnectionFactory(factory);//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class);ObjectMapper om = new ObjectMapper();// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和publicom.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);jacksonSeial.setObjectMapper(om);// 值采用json序列化template.setValueSerializer(jacksonSeial);//使用StringRedisSerializer来序列化和反序列化redis的key值template.setKeySerializer(new StringRedisSerializer());// 设置hash key 和value序列化模式template.setHashKeySerializer(new StringRedisSerializer());template.setHashValueSerializer(jacksonSeial);template.afterPropertiesSet();return template;}}
- 添加pom依赖坐标
- 创建实体类,实现接口UserDetails,实现获取权限方法
@Data @AllArgsConstructor @NoArgsConstructor @Accessors(chain = true) public class UserBean implements UserDetails {private String account;private String username;private String password;private String role;@JSONField(serialize = false)private List<SimpleGrantedAuthority> authorities;@Overridepublic Collection<? extends GrantedAuthority> getAuthorities() {if (authorities != null) {return authorities;}authorities = new ArrayList<>();if(null!=role){SimpleGrantedAuthority simpleGrantedAuthority = new SimpleGrantedAuthority(role);authorities.add(simpleGrantedAuthority);}return authorities;}@Overridepublic boolean isAccountNonExpired() {return true;}@Overridepublic boolean isAccountNonLocked() {return true;}@Overridepublic boolean isCredentialsNonExpired() {return true;}@Overridepublic boolean isEnabled() {return true;} }
- 创建mapper接口,编写sql语句
@Mapper public interface UserBeanMapper {//根据账号查询用户信息@Select("select * from tb_user where account=#{account}")UserBean findUserById(@Param("account")String account); }
- 创建service层登录接口
public interface UserBeanService {R login(String account,String password); }
- 实现service层接口
@Service public class UserServiceImpl implements UserBeanService {@Autowiredprivate AuthenticationManager authenticationManager;@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overridepublic R login(String account, String password) { //创建用户身份验证UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(account, password);Authentication authenticate = authenticationManager.authenticate(usernamePasswordAuthenticationToken);if(null==authenticate){return R.fail("账户名或密码错误");} //以hash方式存储redis中redisTemplate.boundHashOps(account).put(account, JSON.toJSONString(authenticate.getPrincipal())); //设置redis过期时间redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);return R.success(JwtUtil.createJWT(account));} }
- 创建controller层
@RestController public class UserBeanController {@Autowiredprivate UserBeanService userBeanService;//登录@PostMapping("/login")public R login(@RequestParam("account") String account, @RequestParam("password") String password){return userBeanService.login(account,password);}//权限测试@GetMapping("/test")@PreAuthorize("hasAuthority('test')")public R test(){return R.success("这是一条提示消息","test");} }
security相关代码配置
- 这里使用jwt令牌,创建jwt工具类
/*** JWT工具类*/ public class JwtUtil {//有效期为public static final Long JWT_TTL = 60 * 60 *1000L;// 60 * 60 *1000 一个小时//设置秘钥明文public static final String JWT_KEY = "mingwen";public static String getUUID(){String token = UUID.randomUUID().toString().replaceAll("-", "");return token;}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @return*/public static String createJWT(String subject) {JwtBuilder builder = getJwtBuilder(subject, null, getUUID());// 设置过期时间return builder.compact();}/*** 生成jtw* @param subject token中要存放的数据(json格式)* @param ttlMillis token超时时间* @return*/public static String createJWT(String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, getUUID());// 设置过期时间return builder.compact();}private static JwtBuilder getJwtBuilder(String subject, Long ttlMillis, String uuid) {SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;SecretKey secretKey = generalKey();long nowMillis = System.currentTimeMillis();Date now = new Date(nowMillis);if(ttlMillis==null){ttlMillis=JwtUtil.JWT_TTL;}long expMillis = nowMillis + ttlMillis;Date expDate = new Date(expMillis);return Jwts.builder().setId(uuid) //唯一的ID.setSubject(subject) // 主题 可以是JSON数据.setIssuer("sanyue") // 签发者.setIssuedAt(now) // 签发时间.signWith(signatureAlgorithm, secretKey) //使用HS256对称加密算法签名, 第二个参数为秘钥.setExpiration(expDate);}/*** 创建token* @param id* @param subject* @param ttlMillis* @return*/public static String createJWT(String id, String subject, Long ttlMillis) {JwtBuilder builder = getJwtBuilder(subject, ttlMillis, id);// 设置过期时间return builder.compact();}/*** 生成加密后的秘钥 secretKey* @return*/public static SecretKey generalKey() {byte[] encodedKey = Base64.getDecoder().decode(JwtUtil.JWT_KEY);SecretKey key = new SecretKeySpec(encodedKey, 0, encodedKey.length, "AES");return key;}/*** 解析** @param jwt* @return* @throws Exception*/public static Claims parseJWT(String jwt) throws Exception {SecretKey secretKey = generalKey();return Jwts.parser().setSigningKey(secretKey).parseClaimsJws(jwt).getBody();}}
- 创建jwt过滤器
@Component public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {@Autowiredprivate RedisTemplate<String,Object> redisTemplate;@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String token = request.getHeader("token");if (!StringUtils.hasText(token)) {filterChain.doFilter(request, response);return;}String account = null; //校验tokentry {Claims claims = JwtUtil.parseJWT(token);account = claims.getSubject();} catch (Exception e) {e.printStackTrace();throw new RuntimeException("非法token");} //判断redis该用户是否超时存在if(Boolean.FALSE.equals(redisTemplate.boundHashOps(account).hasKey(account))){throw new RuntimeException("用户登录超时请重新登录");} //取出该用户相关信息 同时延长redis存储时间String redisUserObj = redisTemplate.boundHashOps(account).get(account).toString();redisTemplate.boundHashOps(account).expire(100000, TimeUnit.MILLISECONDS);UserBean userBean = JSON.parseObject(redisUserObj, UserBean.class); //将用户信息,及权限交给securityUsernamePasswordAuthenticationToken authenticationToken=new UsernamePasswordAuthenticationToken(userBean,null,userBean.getAuthorities());SecurityContextHolder.getContext().setAuthentication(authenticationToken);filterChain.doFilter(request, response);} }
- 继承security适配器,配置security
@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfiguration extends WebSecurityConfigurerAdapter {@Autowiredprivate JwtAuthenticationTokenFilter jwtAuthenticationTokenFilter;//密码校验规则@Beanpublic BCryptPasswordEncoder passwordEncoder() {return new BCryptPasswordEncoder();}@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception {return super.authenticationManagerBean();}@Overrideprotected void configure(HttpSecurity http) throws Exception {http//关闭csrf.csrf().disable()//不通过Session获取SecurityContext.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers("/login").anonymous()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated();//把token校验过滤器添加到过滤器链中http.addFilterBefore(jwtAuthenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);}@Overridepublic void configure(WebSecurity web) throws Exception {web.ignoring().antMatchers("/login/**","/logout/**");} }
- 实现接口UserDetailsService 并实现方法,走我们自己的业务逻辑
@Service public class UserDetailsServiceImpl implements UserDetailsService {@Autowiredprivate UserBeanMapper userBeanMapper;@Overridepublic UserDetails loadUserByUsername(String account) throws UsernameNotFoundException {return userBeanMapper.findUserById(account);} }
启动项目
- 启动类
@SpringBootApplication public class SecurityApplication {public static void main(String[] args) {ConfigurableApplicationContext run = SpringApplication.run(SecurityApplication.class, args);BCryptPasswordEncoder bean = run.getBean(BCryptPasswordEncoder.class);System.out.println(bean.encode("123456"));} }
- 测试数据
- admin登录
- admin访问对应权限方法
- zhangsan登录
- zhangsan访问权限方法
写的不怎么样,希望对大家有用,希望大家多多指点~~~