Spring security + oauth2.0 + redis + mybatis plus 搭建微服务
上个星期一个朋友请求帮忙,让我搭建一个分布式授权中心的微服务,之前我也没搭建过,在网上撸了几天前辈们写的技术博客,搞出个模型,分享给大家:
前辈们博客地址:
OAuth2.0 原理:https://blog.csdn.net/tclzsn7456/article/details/79550249
JWT 原理:https://baijiahao.baidu.com/s?id=1608021814182894637&wfr=spider&for=pc
以下是代码,我这个是通过密码模式进行认证的:
0.目录结构:
1.引入依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</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-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.3.1</version>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.0.7.1</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
2.编写配置类 AuthorizationParam 并在application.yml 中填写具体参数:
@Data
@ConfigurationProperties(prefix = "authorizationparam")
public class AuthorizationParam {
private String clientId; //客户端id
private String secret; //(可信客户端需要)客户端密钥
private String[] scopes; //客户受限范围
private String authorizedGrantTypes; // 授权客户端使用的授权类型
// private String authorities;//授予客户端的权限
private int tokenExpire;//token过期时间
private int tokenRefresh;//token 刷新时间
}
在application.yml 中填写具体参数:
authorizationparam:
client-id: 123456 #客户端id
secret: 123456 #(可信客户端需要)客户端密钥
scopes: read,write #客户受限范围
authorized-grant-types: password #授权客户端使用的授权类型
token-expire: 10000 #token过期时间
token-refresh: 1500 #token刷新时间
debug: true
3.编写OAuth2.0配置类,注意,这里我使用redis来存储令牌(token)和具体的用户信息,这边便于后期水平扩张:
package com.lmolong.config;
import org.springframework.beans.factory.annotation.Autowired;
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.core.userdetails.UserDetailsService;
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.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.redis.RedisTokenStore;
/***
* OAuth 相关配置
*/
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {
private static final String SECRETPREFIX = "{noop}"; //spring security5 之后需要
@Autowired
private AuthenticationManager authenticationManager; //认证管理者
@Autowired
private UserDetailsService userDetailsService; // 用户信息服务
@Autowired
private TokenStore tokenStore; //保存令牌数据栈
@Autowired
private AuthorizationParam authorizationParam;
@Override
public void configure(ClientDetailsServiceConfigurer clents) throws Exception {
clents.inMemory()
.withClient(authorizationParam.getClientId()) //客户端ID
.authorizedGrantTypes(authorizationParam.getAuthorizedGrantTypes(),"refresh_token")//设置验证方式
.scopes(authorizationParam.getScopes())
// .secret("{noop}secret")
.secret(SECRETPREFIX+authorizationParam.getSecret())
.accessTokenValiditySeconds(authorizationParam.getTokenExpire()) //token过期时间
.refreshTokenValiditySeconds(authorizationParam.getTokenRefresh());//refresh过期时间
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints){
endpoints.tokenStore(tokenStore)
.authenticationManager(authenticationManager)
.userDetailsService(userDetailsService);
}
@Bean
public TokenStore tokenStore(RedisConnectionFactory redisConnectionFactory){
// return new InMemoryTokenStore(); //使用内存存储令牌 tokeStore
return new RedisTokenStore(redisConnectionFactory); //使用redis存储令牌
}
}
4.编写web拦截、资源拦截 配置:
package com.lmolong.config;
import cn.hutool.crypto.SecureUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.authentication.configuration.GlobalAuthenticationConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.password.PasswordEncoder;
@Configuration
public class WebSecurityConfiguration extends GlobalAuthenticationConfigurerAdapter {
@Autowired
private UserDetailsService userDetailsService;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(new PasswordEncoder() {
@Override
public String encode(CharSequence charSequence)
{
return charSequence.toString();
//return SecureUtil.md5(charSequence.toString());
}
@Override
public boolean matches(CharSequence charSequence, String s) {
//return SecureUtil.md5(charSequence.toString()).equals(s);
return charSequence.toString().equals(s);
}
});
// auth.inMemoryAuthentication().passwordEncoder(new BCryptPasswordEncoder()).withUser("user1").password(new BCryptPasswordEncoder().encode("123456")).roles("USER");
}
}
package com.lmolong.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
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;
@Configuration
@EnableResourceServer
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers(HttpMethod.OPTIONS).permitAll()
.anyRequest().authenticated()
.and().httpBasic()
.and().csrf().disable();
}
}
5.这里配置密码的加密方式,这里我暂时未加密:
package com.lmolong.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
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.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
//对任何请求做拦截,如果是完整认证的话,就允许访问
http.authorizeRequests().anyRequest().fullyAuthenticated();
//配置登陆连接,允许访问 --认证接口直接调用/oauth/token
http.formLogin().loginPage("/login").failureUrl("/login?code=").permitAll();
//配置登出连接,允许访问
http.logout().logoutUrl("/logout").permitAll();
http.authorizeRequests().antMatchers("/oauth/authorize").permitAll();
}
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
6.扩张UserDetailService
package com.lmolong.service;
import org.springframework.security.core.userdetails.UserDetailsService;
//后期在此新增UserService的业务接口
public interface UserService extends UserDetailsService {
}
7.实现 UserService,扩展用户认证功能:
package com.lmolong.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.lmolong.authbean.AuthUserDetail;
import com.lmolong.mapper.TUserMapper;
import com.lmolong.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Primary;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import com.lmolong.pojo.TUser;
@Primary
@Service
public class UserServiceImpl implements UserService {
@Autowired
private TUserMapper tUserMapper;
@Override
public AuthUserDetail loadUserByUsername(String username) throws UsernameNotFoundException {
TUser param =new TUser();
param.setUsername(username);
TUser tUser = tUserMapper.selectOne(new QueryWrapper<>(param));
if(tUser==null){
throw new UsernameNotFoundException("用户不存在");
}else{
return UserDetailConverter.convert(tUser);
}
}
private static class UserDetailConverter {
static AuthUserDetail convert(TUser user) {
return new AuthUserDetail(user);
}
}
}
8.编写认证数据库实体类,注意,这里我用了lombok:
package com.lmolong.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class TUser implements Serializable {
private Long id;
private String username;
private String password;
}
9.对应的Auth2.0权限封装类:
package com.lmolong.authbean;
import lombok.Data;
import org.springframework.security.core.userdetails.User;
import com.lmolong.pojo.TUser;
import java.util.Collections;
@Data
public class AuthUserDetail extends User {
private TUser tUser;
public AuthUserDetail(TUser user) {
super(user.getUsername(), user.getPassword(), true, true, true, true, Collections.EMPTY_SET);
this.tUser= user;
}
}
10.编写对应mapper接口:
package com.lmolong.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.lmolong.pojo.TUser;
public interface TUserMapper extends BaseMapper<TUser> {
}
11.注意,在启动类中,我们要加上MapperScan注解:
package com.lmolong;
import com.lmolong.config.AuthorizationParam;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
@SpringBootApplication
@EnableConfigurationProperties({AuthorizationParam.class})
@MapperScan("com.lmolong.mapper")
public class SpringcloudOauth2Application {
public static void main(String[] args) {
SpringApplication.run(SpringcloudOauth2Application.class, args);
}
}
12.编写获取用户信息接口:
package com.lmolong.controller;
import com.lmolong.authbean.AuthUserDetail;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RestController;
import com.lmolong.pojo.TUser;
@RestController
public class UserController {
@Autowired
private TokenStore tokenStore;
@PostMapping("/auth")
public String auth(@RequestHeader("Authorization") String auth){
AuthUserDetail authUserDetail = (AuthUserDetail) tokenStore.readAuthentication(auth.split(" ")[1]).getPrincipal();
TUser tUser = authUserDetail.getTUser();
return tUser.getUsername()+":"+tUser.getPassword();
}
}
13.测试:
通过postman调用:http://localhost:8080/oauth/token 获取令牌
获取token成功:
使用 Redis Desktop manager 查看数据,发现数据已经存到redis中了:
访问接口,根据token获取用户信息:
获取成功。
至此,这个授权微服务整合完毕,当然,可能还有很多不完善的地方,期待大神指导,让我能更加完善它,在此感谢。
源码地址:https://gitee.com/lmolong/springcloud-oauth2
作者:L墨龙
原文:https://my.oschina.net/linwl/blog/2998036
Spring security + oauth2.0 + redis + mybatis plus 搭建微服务的更多相关文章
- springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)
项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖 ...
- Spring Security OAuth2.0认证授权二:搭建资源服务
在上一篇文章[Spring Security OAuth2.0认证授权一:框架搭建和认证测试](https://www.cnblogs.com/kuangdaoyizhimei/p/14250374. ...
- Spring Security OAuth2.0 - AuthorizationServer和ResourceServer分离
<Spring Security实现OAuth2.0授权服务 - 基础版>和<Spring Security实现OAuth2.0授权服务 - 进阶版>两篇文章中介绍如何搭建OA ...
- Spring Security OAuth2.0认证授权三:使用JWT令牌
Spring Security OAuth2.0系列文章: Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二: ...
- Spring Security OAuth2.0认证授权四:分布式系统认证授权
Spring Security OAuth2.0认证授权系列文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授 ...
- Spring Security OAuth2.0认证授权五:用户信息扩展到jwt
历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...
- Spring Security OAuth2.0认证授权六:前后端分离下的登录授权
历史文章 Spring Security OAuth2.0认证授权一:框架搭建和认证测试 Spring Security OAuth2.0认证授权二:搭建资源服务 Spring Security OA ...
- 【OAuth2.0】Spring Security OAuth2.0篇之初识
不吐不快 因为项目需求开始接触OAuth2.0授权协议.断断续续接触了有两周左右的时间.不得不吐槽的,依然是自己的学习习惯问题,总是着急想了解一切,习惯性地钻牛角尖去理解小的细节,而不是从宏观上去掌握 ...
- 基于spring boot2.0+spring security +oauth2.0+ jwt微服务架构
github地址:https://github.com/hankuikuide/microservice-spring-security-oauth2 项目介绍 该项目是一个演示项目,主要演示了,基于 ...
随机推荐
- Virtualbox虚拟机安装RouterOS
一,下载 vdi文件https://mikrotik.com/download Cloud Hosted Routerhttps://download.mikrotik.com/routeros/6. ...
- linux 网络设备,网卡配置 ,相关
网络设备,网卡配置: Eth0是物理网卡:唯一mac地址,Bcast:广播地址,MAsk:子网掩码, Lo:系统自带的回环的ip地址,可以做一些基本的测试应用,比如没有网卡就用127.0.0.1, r ...
- 激活win10企业长期服务版
win10 2016 长期服务版的ISO文件中本身就带有KMS激活KEY,不用输入任何KEY,连接网络进入CMD,只要输入:slmgr /skms kms.digiboy.irslmgr /ato这两 ...
- 配置composer代理
composer config -g repo.packagist composer https://packagist.phpcomposer.com
- ubuntu:undefined reference to `snd_pcm_open'
这几天在做一个局域网的对讲机和广播系统. 需要用到alsa的库来进行音频采集和播放. 但是在编译程序的时候有个比较奇怪的问题. undefined reference to `snd_pcm_open ...
- jquery中的attr与prop
http://www.cnblogs.com/Showshare/p/different-between-attr-and-prop.html
- FFMPEG more samples than frame size (avcodec_encode_audio2) 的解决方案
在实际的项目中,从音频设备采集到的音频的类型和编码器类型(aac ,amr)通常是不一致的. 那么我们首先需要做重采样的过程.利用swr_convert 重新采样. 这时候我们可能会遇到另外一个问题. ...
- linux应用之perl环境的安装(centos)
1.安装Perl环境 yum install perl*这个命令基本上把perl的模块给安装齐了.yum install cpanCPAN这个就不用说了吧,大家都懂. 如果你对perl模块版本要求比较 ...
- java运行Linux命令
<%@ page language="java" import="java.util.*,java.io.*" pageEncoding="UT ...
- flume 日志收集单节点
flume 是 cloudera公司研发的日志收集系统,采用3层结构:1. agent层,用于直接收集日志;2.connect 层,用于接受日志; 3. 数据存储层,用于保存日志.由一到多个maste ...