SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token

       写在前面:当我们开始使用Security的时候,常常因为各种注入,而迷糊,但是很害怕使用security,感觉很重很难用!再加入oauth2更难搞,今天我就写点自己的配置理解,希望对大家有帮助!(会提供一个可以使用的源码,放在最后,如果你不想看内容,可以直接下载!)

一: spring security 的核心功能主要包括:

  • 认证 (你是谁)
  • 授权 (你能干什么)
  • 攻击防护 (防止伪造身份)

        oauth2根据使用场景不同,分成了4种模式,感兴趣的可以去了解,我们主要用密码模式,说白了就是账号密码登录模式

我们主要用认证 ——授权 ——发放Token

二:直接开始

1.核心依赖(主要就是这两个,其他的随便导下就行了,reids,mysql的自己弄下)

		<!--security依赖--> 		<dependency> 			<groupId>org.springframework.boot</groupId> 			<artifactId>spring-boot-starter-security</artifactId> 		</dependency> 		<!--oauth2依赖--> 		<dependency> 			<groupId>org.springframework.security.oauth</groupId> 			<artifactId>spring-security-oauth2</artifactId> 			<version>2.3.3.RELEASE</version> 		</dependency>

2.Yml配置文件(为了节省空间,其他配置不放了,redis,mysql的大家自己根据自己情况使用)

# oauth2.0配置 client:   oauth2:     client-id: appId # 客户端标识Id     secret: 123456 # 客户端安全码     # 授权类型     grant_types:       - password       - refresh_token     # token 有效期     token-validity-time: 3600     refresh-token-validity-time: 3600     # 客户端访问范围     scopes:       - api       - all

3.下面就开始核心代码编写了

第一就是security的配置类,该类相当核心,主要注入几个核心功能,先贴代码

package io.springboot.netty.oauth2server;  import org.apache.commons.codec.digest.DigestUtils; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;  import javax.annotation.Resource;  /**                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          * Security 配置类  *  * @author zheng  */ @Configuration @EnableWebSecurity public class SecurityConfiguration extends WebSecurityConfigurerAdapter {      /**      * 注入redis 连接工厂      */     @Resource     private RedisConnectionFactory redisConnectionFactory;      /**      * 初始化 redisTokenStore 用户将token 放入redis      * @return      */     @Bean     public RedisTokenStore redisTokenStore(){         RedisTokenStore redisTokenStore = new RedisTokenStore(redisConnectionFactory);         redisTokenStore.setPrefix("TOKEN:");         return redisTokenStore;     }      /**      * 初始化密码编码器 MD5加密      * @return      */     @Bean     public PasswordEncoder passwordEncoder(){         return new PasswordEncoder() {              /**              * 加密              * @param rawPassword 原始密码              * @return              */             @Override             public String encode(CharSequence rawPassword) {                 return DigestUtils.md5Hex(rawPassword.toString());             }              /**              * 校验密码              * @param rawPassword 原始密码              * @param encoderPassword 加密后密码              * @return              */             @Override             public boolean matches(CharSequence rawPassword, String encoderPassword) {                 return DigestUtils.md5Hex(rawPassword.toString()).equals(encoderPassword);             }         };     }      /**      * 初始化管理对象      */     @Override     @Bean     public AuthenticationManager authenticationManager() throws Exception {         return super.authenticationManager();     }      /**      * 放行 和 认证规则      * @param http      * @throws Exception      */     @Override     protected void configure(HttpSecurity http) throws Exception {         http.csrf().disable()                 .authorizeRequests()                 // 放行                 .antMatchers("/oauth/**", "/actuator/**")                 .permitAll()                 .and()                 .authorizeRequests()                 .anyRequest()                 // 其他需要拦截                 .authenticated();      } } 

        1.RedisConnectionFactory 注入redis的连接工厂,

        2.初始化 redisTokenStore 用户将token 放入redis,也可以放入内存当中,建议放入redis中。

        3.初始化密码编码器,使用MD5,亦可以换成security的加密方式。重写加密方法-encode,修改加密方式,重写校验方法-matches.

        4.初始化 AuthenticationManager认证管理对象

        5.重写config方法,配置放行和认证 、/oauth 等会我们重写它,做为登录方法使用

        "/oauth/**", "/actuator/**"

这个方法还是比较简单的,主要为了注入bean和配置一个拦截方法

授权配置类
  import io.springboot.netty.entity.LoginUser; import io.springboot.netty.service.impl.UserServiceImpl; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken; import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer; import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;  import javax.annotation.Resource; import java.util.LinkedHashMap;  /**  * 授权配置类  * @author zheng  */ @Configuration @EnableAuthorizationServer public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {      @Autowired     private UserServiceImpl userService;      @Resource     private RedisTokenStore redisTokenStore;        /**      * 管理器      */     @Resource     private AuthenticationManager authenticationManager;      /**      * 密码编码器      */     @Resource     private PasswordEncoder passwordEncoder;      /**      * 客户端配置类      */     @Resource     private ClientOauth2DataConfiguration oauth2DataConfiguration;      /**      * 客户端配置授权模型      * @param clients      * @throws Exception      */     @Override     public void configure(ClientDetailsServiceConfigurer clients) throws Exception {         clients.inMemory().withClient(oauth2DataConfiguration.getClientId())                 .secret(passwordEncoder.encode(oauth2DataConfiguration.getSecret()))                 .authorizedGrantTypes(oauth2DataConfiguration.getGrantTypes()) // token 授权类型                 .accessTokenValiditySeconds(oauth2DataConfiguration.getTokenValidityTime()) // token 过期时间                 .refreshTokenValiditySeconds(oauth2DataConfiguration.getRefreshTokenValidityTime()) // token 刷新过期时间                 .scopes(oauth2DataConfiguration.getScopes());     }      /**      * 配置令牌端点的安全约束      * @param security      * @throws Exception      */     @Override     public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {         // 允许访问 token 的公钥,默认 /oauth/token_key 受保护的         security.tokenKeyAccess("permitAll()")                 // 允许访问 token 的状态,默认 /oauth/check_token 受保护的                 .checkTokenAccess("permitAll()");     }      @Override     public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {             // 认证器         endpoints.authenticationManager(authenticationManager)                 // 具体登陆方法                 .userDetailsService(userService)                 // token 存储方式 redis                 .tokenStore(redisTokenStore)                 // 令牌增强对象 , 增强返回的结果                 .tokenEnhancer((accessToken, authentication) ->{                     // 获取用户信息,然后设置                     LoginUser loginUser = (LoginUser) authentication.getPrincipal();                     LinkedHashMap<String, Object> map = new LinkedHashMap<>();                     map.put("userId",loginUser.getUserId());                     map.put("usernmae",loginUser.getUsername());                     map.put("logo", loginUser.getLogo());                     DefaultOAuth2AccessToken token = (DefaultOAuth2AccessToken) accessToken;                     token.setAdditionalInformation(map);                     return token;                 });      } } 

这个方法中,我们可以看到上一个方法注入的几个bean,并且重写三个配置类1.config,configure(ClientDetailsServiceConfigurer clients),客户端配置授权模型,就是我们所说oauth2的四个模式,我们就用一个密码模式。

2.configure(AuthorizationServerSecurityConfigurer security),配置令牌端点的安全约束,上面我们也提到了重写/oauth/**接口来实现登录,在这里要先给它放行,否则我们都请求不到!

3.configure(AuthorizationServerEndpointsConfigurer endpoints),这里就是配置认证器了,我们先将管理器注入(authenticationManager),然后实现具体登录方法,主要就是为了登录校验密码,然后设置token的存放方式,最后对令牌做一个增强,就是要返回那些SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token

 图上可以看下参数,账号密码,没什么说的,grant_type = password,就是我上面提到的密码模式,scope,指的是接口可访问的范围,这两个参数在YML文件中,都配置了,在请求的时需要传递,在Body旁边,有个认证,postman中为英文认证单词,点击进入

SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token

 这两个参数需要从yml读取,也就是client-id和secret的值,我这里选择配置文件加载,主要就是为了验证前后端是否有资格使用登录接口,如果配置的值不一致,也是请求不了接口的。还有一种方式是从数据库中加载,security也提供了相应的方式,更加灵活点。

{ 	"userId": 10148629, 	"usernmae": "抽奖专用小马甲", 	"logo": "http://logo.sqsjt.net/upfiles/user/face/90/9005c1be3839c52c52c97e7589e46d5c.jpg?5F1FF05C", 	"accessToken": "5bb9602b-89bb-42d6-a4b6-3d35db9bea2a", 	"expireIn": 2489, 	"scopes": [ 		"api" 	], 	"refreshToken": "0979b94e-3f85-4e5b-afa2-719f0ae17bb2" }

请求成功后,就是返回了这些,从参数可以看到我们实现的令牌增强功能,返回了自定义的三个参数,userId,username,logo,可以配置更多参数,剩下的token参数则是在 OauthController.custom中配置了。

请求成功后,我们可以在redis中看到Token的相关信息,如下图

SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token

        可是我们用token去请求接口的时候,还是会提示403,找不到相关资源,这个是因为我们还没有配置资源配置类

package security.oauth2.oauth2Server;  import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer; import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter; import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer; import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;  import javax.annotation.Resource;  /**  * @author zheng  */ @Configuration @EnableResourceServer public class ResourceServerConfig extends ResourceServerConfigurerAdapter {      @Resource     private MyAuthenticationEntryPoint myAuthenticationEntryPoint;      @Resource     private RedisTokenStore redisTokenStore;      @Override     public void configure(HttpSecurity http) throws Exception {         http.authorizeRequests().anyRequest()                 .authenticated()                 .and()                 .requestMatchers().antMatchers("/user/**");     }      @Override     public void configure(ResourceServerSecurityConfigurer resources) throws Exception {         // 设置token存储         resources.tokenStore(redisTokenStore);         // 设置验证失败         resources.authenticationEntryPoint(myAuthenticationEntryPoint);     } } 

重写config方法,验证/user/**开头的请求接口,这里可以根据具体业务配置,我们写一个UserController,来查询下用户的基本信息。

package security.oauth2.controller;  import org.springframework.security.core.Authentication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController;   /**  * 用户中心  * @author zheng  */ @RestController public class UserController {      @GetMapping("user/me")     public Object postAccessToken(Authentication authentication){         Object principal = authentication.getPrincipal();         return principal;     } } 

直接请求接口,使用/oauth/token返回的access_token,可以看出来,返回了用户基本信息

SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token

用户表结构

/*  Navicat Premium Data Transfer   Source Server         : localhost  Source Server Type    : MySQL  Source Server Version : 50725  Source Host           : localhost:3306  Source Schema         : yami_shops   Target Server Type    : MySQL  Target Server Version : 50725  File Encoding         : 65001   Date: 24/08/2021 00:33:39 */  SET NAMES utf8mb4; SET FOREIGN_KEY_CHECKS = 0;  -- ---------------------------- -- Table structure for manor_user -- ---------------------------- DROP TABLE IF EXISTS `manor_user`; CREATE TABLE `manor_user`  (   `id` int(11) NOT NULL AUTO_INCREMENT,   `guide_type` tinyint(1) DEFAULT 0 COMMENT '是否需要引导(默认为0,需要 1:不需要)',   `level` int(255) DEFAULT 1 COMMENT '用户等级',   `experience` int(255) DEFAULT 0 COMMENT '用户经验值',   `fruits_type` tinyint(1) DEFAULT 0 COMMENT '种植水果类型 (默认0:未种  1.桃树,2.梨树,3.西瓜,4.草莓,5.葡萄)',   `fruits_exp` int(255) DEFAULT 0 COMMENT '果树经验值',   `user_id` int(20) NOT NULL COMMENT '用户id',   `fruits_level` tinyint(2) DEFAULT 0 COMMENT '果树等级',   `set_bullet_arr` tinyint(1) DEFAULT 1 COMMENT '弹幕开启:0 关闭 1:开启',   `create_time` datetime(0) DEFAULT NULL COMMENT '创建时间',   `state` tinyint(1) DEFAULT 1 COMMENT '状态:1 启用 0 禁用',   `manure_num` int(11) DEFAULT 0 COMMENT '肥料',   `water_num` int(11) DEFAULT 0 COMMENT '水',   `card_num` int(11) DEFAULT NULL COMMENT '加速卡',   `add_sign` int(255) DEFAULT 0 COMMENT '本月前用户签到总数',   `username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '用户名',   `logo` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '头像',   `password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT '密码',   PRIMARY KEY (`id`) USING BTREE,   UNIQUE INDEX `user_id`(`id`, `user_id`) USING BTREE ) ENGINE = InnoDB AUTO_INCREMENT = 20210513 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '广电庄园 —— 用户信息表' ROW_FORMAT = Dynamic;  -- ---------------------------- -- Records of manor_user -- ---------------------------- INSERT INTO `manor_user` VALUES (20210511, 1, 30, 1268710, 1, 71120, 10148629, 7, 0, '2021-06-02 11:39:33', 1, 245, 910, 2, 7, '抽奖专用小马甲', 'xxxxxxxxxxxxxxx', 'e10adc3949ba59abbe56e057f20f883e');  SET FOREIGN_KEY_CHECKS = 1; 

 三:结束

        到这里,我们可以看出来,集成已经完成,其实也没有几个类,就搞定了token的分发,大家可以直接用项目源码去自己调试一下,每隔模块都写得很清晰。

        demo,我已经测试成功!!!,所以出现问题,一定是你没有配置好,请不要说项目不能使用的话。虚心接受指导,但不接受瞎xxxxx

         码云地址:https://gitee.com/jijiuc/oauth2_securtiy.git

               土豪地址:https://download.csdn.net/download/weixin_38061191/21472467

版权声明:玥玥 发表于 2021-08-26 1:04:06。
转载请注明:SpringSecurity+SpringSecurityOauth2集成实现权限框架,Redis分发Token | 女黑客导航