Spring Boot整合oauth2.0搭建统一授权服务(密码模式)

前言

写这个博客得原因是最近想要将自己得api单独发布给第三方使用,但是又不想被别人滥用,所以想弄一个授权服务,但是网上关于oauth2.0的资料层出不穷,看了之后完全不明白应该如果实际的去整合,现在基本成功后记录下来。

关于oauth2.0的概念以及相关的知识等可以建议参阅理解OAuth 2.0。

准备

新建一个Spring Boot的web项目并导入一下依赖:


	org.springframework.security.oauth
	spring-security-oauth2


	org.springframework.boot
	spring-boot-starter-security


	org.springframework.boot
	spring-boot-starter-web

配置

配置EnableAuthorizationServer

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationConfig extends AuthorizationServerConfigurerAdapter {


    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserDetailsService userService;

    @Autowired
    private TokenStore tokenStore;

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.inMemory()
                .withClient("test")//客户端ID
                .authorizedGrantTypes("password", "refresh_token")//设置验证方式
                .scopes("read", "write")
                .secret("123456")
                .accessTokenValiditySeconds(10000) //token过期时间
                .refreshTokenValiditySeconds(10000); //refresh过期时间
    }

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        endpoints.tokenStore(tokenStore)
                .authenticationManager(authenticationManager)
                .userDetailsService(userService); //配置userService 这样每次认证的时候会去检验用户是否锁定,有效等
    }

    @Bean
    public TokenStore tokenStore() {
        //使用内存的tokenStore
        return new InMemoryTokenStore();
    }
}

UserService接口定义如下:

public interface UserService extends UserDetailsService {
    //后期在此新增UserService的业务接口
}

其中UserDetailsService只包含一个需要实现的方法,具体实现:

@Primary
@Service("userService")
public class UserServiceImpl implements UserService {

    private final static Set users = new HashSet<>();

    static {
        users.add(new User(1, "test-user1", "123451"));
        users.add(new User(2, "test-user2", "123452"));
        users.add(new User(3, "test-user3", "123453"));
        users.add(new User(4, "test-user4", "123454"));
    }

    @Override
    public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        Optional user = users.stream()
                .filter((u) -> u.getUserName().equals(s))
                .findFirst();
        if (!user.isPresent())
            throw new UsernameNotFoundException("there's no user founded!");
        else
            return UserDetailConverter.convert(user.get());
    }

    private static class UserDetailConverter {
        static UserDetails convert(User user) {
            return new MyUserDetails(user);
        }
    }
}

根据方法名很容易明白spring 的组件会调用此方法去获取到用户的信息并去验证。

这里的用户信息直接写死的,实际中可以用jdbc或者其他配置等方式。

同时loadUserByUsername方法要求返回一个UserDetails接口:

public interface UserDetails extends Serializable {
    Collection getAuthorities();

    String getPassword();

    String getUsername();

    boolean isAccountNonExpired();

    boolean isAccountNonLocked();

    boolean isCredentialsNonExpired();

    boolean isEnabled();
}

并且spring已经有了它的一个实现:org.springframework.security.core.userdetails.User类

由于User这个名字很容易和我们项目中的实体User重名这里选择继承这个类自己实现一个UserDetails:

/**
 * 自定义UserDetails类 携带User实例
 */
public class MyUserDetails extends User {

    private com.example.oauth.pojo.User user;

    public MyUserDetails(com.example.oauth.pojo.User user) {
        super(user.getUserName(), user.getPassword(), true, true, true, true, Collections.EMPTY_SET);
        this.user = user;
    }

    public com.example.oauth.pojo.User getUser() {
        return user;
    }

    public void setUser(com.example.oauth.pojo.User user) {
        this.user = user;
    }
}

到此基本的配置就已经完成了,

测试

写一个测试的Controller:

 

@RestController
public class UserController {

    @Autowired
    private TokenStore tokenStore;

    @PostMapping("/bar")
    public String bar(@RequestHeader("Authorization") String auth) {

        MyUserDetails userDetails = (MyUserDetails) tokenStore.readAuthentication(auth.split(" ")[1]).getPrincipal();

        User user = userDetails.getUser();

        return user.getUserName() + ":" + user.getPassword();
    }
}

启动项目:

访问:localhost:8080/bar

返回未授权

访问:localhost:8080/oauth/token获取token

Spring Boot整合oauth2.0搭建统一授权服务(密码模式)_第1张图片

这里的Authrization字段中Basic后面是配置中的clientId + ":" + secret的Base64编码结果

Spring Boot整合oauth2.0搭建统一授权服务(密码模式)_第2张图片

我这里是:test:123456的Base64编码结果

Spring Boot整合oauth2.0搭建统一授权服务(密码模式)_第3张图片

返回token信息:

Spring Boot整合oauth2.0搭建统一授权服务(密码模式)_第4张图片

使用token访问controller:

Spring Boot整合oauth2.0搭建统一授权服务(密码模式)_第5张图片

成功。

github源码戳这里~

你可能感兴趣的:(Spring,Boot)