• 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.目录结构:

    Spring security + oauth2.0 + redis + mybatis plus 搭建微服务

     

    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 获取令牌

    Spring security + oauth2.0 + redis + mybatis plus 搭建微服务

     

    获取token成功:

    Spring security + oauth2.0 + redis + mybatis plus 搭建微服务

     

    使用 Redis Desktop manager 查看数据,发现数据已经存到redis中了:

    Spring security + oauth2.0 + redis + mybatis plus 搭建微服务

     

    访问接口,根据token获取用户信息:

    Spring security + oauth2.0 + redis + mybatis plus 搭建微服务

     

    获取成功。

    至此,这个授权微服务整合完毕,当然,可能还有很多不完善的地方,期待大神指导,让我能更加完善它,在此感谢。

    源码地址:https://gitee.com/lmolong/springcloud-oauth2

    作者:L墨龙

    原文:https://my.oschina.net/linwl/blog/2998036

  • 相关阅读:
    WebView.自动登录
    Android.对话框(AlertDialog/Toast/Snackbar)
    ubuntu解压rar
    sqlserver2005 存储过程模板及调用
    win7 32位下装oracle 10g报未知错误
    oracle下常用查询更新命令(身份证号判断男女,更新语句多表查询)
    如何建立一个android工程
    ubuntu14.04 配置android及sdk等相关操作
    mysql 常用简单的几个命令
    linux的tar简单使用
  • 原文地址:https://www.cnblogs.com/wangsongbai/p/10299742.html
Copyright © 2020-2023  润新知