zoukankan      html  css  js  c++  java
  • Spring Security Oauth2 示例

    所有示例的依赖如下(均是SpringBoot项目)

    pom.xml

    <dependencies>
        <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>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security</groupId>
            <artifactId>spring-security-jwt</artifactId>
        </dependency>
    </dependencies>
    

    一、ResourceServer(资源服务器)

    application.yml

    server:
      port: 8082
      context-path: /resourceserver
    

    启动类

    @SpringBootApplication
    public class ResourceServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(ResourceServerApplication.class, args);
        }
    }
    

    TestController.java(暴露RESTful接口)

    @RestController
    public class TestController {
    
        @GetMapping("/product/{id}")
        public String product(@PathVariable String id) {
            return "product id : " + id;
        }
    
        @GetMapping("/order/{id}")
        public String order(@PathVariable String id) {
            return "order id : " + id;
        }
    
        @GetMapping("/pomer/{id}")
        public String pomer(@PathVariable String id) {
            return "pomer id : " + id;
        }
    }
    

    配置类 ResourceServerConfig(配置JWT形式的token)

    @EnableResourceServer
    @Configuration
    public class ResourceServerConfig {
    
        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            converter.setSigningKey("123");
            return converter;
        }
    }
    

    配置类 MyResourceServerConfigurer(配置访问权限)

    @Configuration
    public class MyResourceServerConfigurer extends ResourceServerConfigurerAdapter {
    
        @Override
        public void configure(HttpSecurity http) throws Exception {
            http
                    .authorizeRequests()
                    .antMatchers("/product/**").permitAll()
                    .antMatchers("/order/**").authenticated()
                    .antMatchers("/pomer/**").access("#oauth2.hasScope('read_profile') and hasAuthority('ADMIN')");
        }
    }
    

    二、AuthorizationServer 授权服务器(授权码模式,authorization code)

    application.yml

    server:
      port: 8081
      context-path: /authorizationserver
    

    启动类

    @SpringBootApplication
    public class AuthorizationServerApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(AuthorizationServerApplication.class, args);
        }
    }
    

    配置类 AuthorizationServerConfig(配置JWT形式的token)

    @EnableAuthorizationServer
    @Configuration
    public class AuthorizationServerConfig {
    
        @Bean
        public TokenStore tokenStore() {
            return new JwtTokenStore(jwtAccessTokenConverter());
        }
    
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConverter() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            converter.setSigningKey("123");
            return converter;
        }
    }
    

    配置类 MyAuthorizationServerConfigurer

    @Configuration
    public class MyAuthorizationServerConfigurer extends AuthorizationServerConfigurerAdapter {
    
        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired
        private TokenStore tokenStore;
        @Autowired
        private JwtAccessTokenConverter jwtAccessTokenConverter;
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.tokenStore(tokenStore)
                    .accessTokenConverter(jwtAccessTokenConverter)
                    .authenticationManager(authenticationManager);
        }
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("clientApp")
                    .secret("123456")
                    .redirectUris("http://localhost:9000/callback")
                    .authorizedGrantTypes("authorization_code")
                    .scopes("read_profile", "read_contacts");
        }
    }
    

    配置类 MyWebSecurityConfigurerAdapter(配置用户名密码)

    @Configuration
    public class MyWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                    .withUser("user").password("123456").authorities("USER").and()
                    .withUser("admin").password("123456").authorities("USER", "ADMIN");
        }
    }
    

    开始测试!打开浏览器访问:

    http://localhost:8081/authorizationserver/oauth/authorize?client_id=clientApp&redirect_uri=http://localhost:9000/callback&response_type=code&scope=read_profile
    

    显示登录页面,输入用户名密码,返回重定向302(授权码位于参数部分)

    http://localhost:9000/callback?code=EWfpi5
    

    根据授权码,请求令牌:

    >  curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=authorization_code&redirect_uri=http://localhost:9000/callback&scope=read_profile&code=EWfpi5"
    
    # clientApp:123456 经Base64编码得 'Y2xpZW50QXBwOjEyMzQ1Ng=='
    POST /authorizationserver/oauth/token HTTP/1.1
    Host: localhost:8081
    Content-Type: application/x-www-form-urlencoded
    Authorization: Basic Y2xpZW50QXBwOjEyMzQ1Ng==
    Cache-Control: no-cache
    Postman-Token: c6c182c7-5df1-46ea-9cb7-130ff250c93c
    
    code=F4QesT&grant_type=authorization_code&redirect_uri=http%3A%2F%2Flocalhost%3A9000%2Fcallback&scope=read_profile
    

    得到令牌:

    {
    "access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho",
    "token_type":"bearer",
    "expires_in":43199,
    "scope":"read_profile",
    "jti":"c2c48a74-b825-4cea-94e7-323ee7d8596d"
    }
    

    根据令牌请求资源

    > curl http://localhost:8082/resourceserver/order/12 -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho"
    
    GET /resourceserver/order/12 HTTP/1.1
    Host: localhost:8082
    Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NTExMTYsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImMyYzQ4YTc0LWI4MjUtNGNlYS05NGU3LTMyM2VlN2Q4NTk2ZCIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.Oc1TN7fMPgNVXX7k8dEw0QqosD7ZKQ198c-Qa2l1Gho
    Cache-Control: no-cache
    Postman-Token: 913a8844-1308-47d8-afa3-a9f288323c20
    

    返回资源

    order id : 12
    

    附:/product/* 允许任何人访问,/order/* 需要用户认证,而 /pomer/* 只允许拥有ADMIN权限的admin用户访问,测试有效

    三、AuthorizationServer 授权服务器(简化模式,implicit)

    只修改配置类 MyAuthorizationServerConfigurer,其余代码不变

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("clientApp")
                    .secret("123456")
                    .redirectUris("http://localhost:9000/callback")
                    .authorizedGrantTypes("implicit")
                    .scopes("read_profile","read_contacts");
        }
    

    开始测试!打开浏览器访问:

    http://localhost:8081/authorizationserver/oauth/authorize?client_id=clientApp&redirect_uri=http://localhost:9000/callback&response_type=token&scope=read_profile&state=xyz
    

    显示登录页面,输入用户名密码,返回重定向302(令牌位于hash部分):

    http://localhost:9000/callback#access_token=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE4NjMxNjMsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImQ2MzYxYzZjLTIyZWYtNDU2ZC1iOGJhLWY4ZTE5MzMwMTBmOSIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.BRwtzF2rFc6w8WECqYETZbkCSDdoOzKdF4Zm_SAZuao&token_type=bearer&state=xyz&expires_in=119&jti=d6361c6c-22ef-456d-b8ba-f8e1933010f9
    

    得到令牌,后续请求资源相同,不再重复叙述

    四、AuthorizationServer 授权服务器(密码模式,resource owner password credentials)

    修改配置类 MyAuthorizationServerConfigurer

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("clientApp")
                    .secret("123456")
                    .authorizedGrantTypes("password")
                    .scopes("read_profile", "read_contacts");
        }
    

    在默认情况下 AuthorizationServerEndpointsConfigurer 配置没有开启密码模式,只有配置了 authenticationManager 才会开启密码模式,如下

    在 MyWebSecurityConfigurerAdapter.java 新增一段代码(配置 authenticationManager Bean)

        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    

    在 MyAuthorizationServerConfigurer.java 新增一段代码(令 AuthorizationServerEndpointsConfigurer 设置 authenticationManager)

        @Autowired
        private AuthenticationManager authenticationManager;
        @Autowired
        private TokenStore tokenStore;
        @Autowired
        private JwtAccessTokenConverter jwtAccessTokenConverter;
    
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
            endpoints.tokenStore(tokenStore)
                    .accessTokenConverter(jwtAccessTokenConverter)
                    .authenticationManager(authenticationManager);
        }
    

    开始测试!请求令牌

    >  curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=password&scope=read_profile&username=user&password=123456"
    

    得到令牌:

    {
    "access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE1NDE5MDk4MTcsInVzZXJfbmFtZSI6InVzZXIiLCJhdXRob3JpdGllcyI6WyJVU0VSIl0sImp0aSI6ImJhZDk1OTI0LTdkYTgtNDUyMy05YzZkLTBkNzY3NTlmYjQ1NiIsImNsaWVudF9pZCI6ImNsaWVudEFwcCIsInNjb3BlIjpbInJlYWRfcHJvZmlsZSJdfQ.gO5_kl8_OBRnj2Dt5glflXAIJrbyioYXezV-ZQ8BxL4",
    "token_type":"bearer",
    "expires_in":43199,
    "scope":"read_profile",
    "jti":"bad95924-7da8-4523-9c6d-0d76759fb456"
    }
    

    得到令牌,后续请求资源相同,不再重复叙述

    五、AuthorizationServer 授权服务器(客户端模式,client credentials)

    只修改配置类 MyAuthorizationServerConfigurer,其余代码不变

        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
            clients.inMemory()
                    .withClient("clientApp")
                    .secret("123456")
                    .authorizedGrantTypes("client_credentials")
                    .scopes("read_profile", "read_contacts");
        }
    

    开始测试!请求令牌

    >  curl -X POST --user clientApp:123456 http://localhost:8081/authorizationserver/oauth/token -H "Content-Type: application/x-www-form-urlencoded" -d "grant_type=client_credentials&scope=read_profile"
    

    得到令牌:

    {
    "access_token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzY29wZSI6WyJyZWFkX3Byb2ZpbGUiXSwiZXhwIjoxNTQxOTEwOTEzLCJqdGkiOiI5MDVjNzc2OS1lNGQ2LTQxYTItYjcyMC1jYzliZWZjYzE5MDQiLCJjbGllbnRfaWQiOiJjbGllbnRBcHAifQ.c6UiHxbCdioCklkCqkLsCG6C8KHwwzajlPka6ut5MJs",
    "token_type":"bearer",
    "expires_in":43199,
    "scope":"read_profile",
    "jti":"905c7769-e4d6-41a2-b720-cc9befcc1904"
    }
    

    得到令牌,后续请求资源相同,不再重复叙述

  • 相关阅读:
    eclipse快捷键失效
    git学习 branch log rebase merge fetch remote add push pull
    解决netty tcp自定义消息格式粘包/拆包问题
    多线程while(!state){}有问题,volatile优化,sleep睡着之后唤醒,刷新变量缓存
    玄学eclipse ,突然所有文件报错,然后,ctrl+a, ctrl+x, ctrl+v就好了
    玄学springboot applicationcontext.getBean(用类名String还是类型Class), getBean(..)的调用场景结果不同?getBean(..)还会阻塞?@DependsOn按照名称依赖,那么getBean用类名String
    玄学yml,被@ActiveProfiles注解误导
    玄学yml,被@ActiveProfiles注解误导
    java动态代理,多服务实例,线程安全target,注解,面向切面修改具有注解的方法行为,ThreadLocal<Object>
    java键盘输入方法-
  • 原文地址:https://www.cnblogs.com/pomer-huang/p/pomer_huang.html
Copyright © 2011-2022 走看看