• spring security oauth 开发sso单点登录


    1. 创建项目
    sso-demo 父项目
    sso-server 认证服务器
    sso-client1
    sso-client2
    引入jar包
     1.创建 sso-demo 项目 pom.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.imooc.sso</groupId>
        <artifactId>sso-demo</artifactId>
        <packaging>pom</packaging>
        <version>1.0.0-SNAPSHOT</version>
        <modules>
            <module>sso-server</module>
            <module>sso-client1</module>
            <module>sso-client2</module>
        </modules>
    
        <!--由spring platform 来管理版本依赖版本-->
        <dependencyManagement>
            <dependencies>
                <dependency>
                    <groupId>io.spring.platform</groupId>
                    <artifactId>platform-bom</artifactId>
                    <version>Brussels-SR4</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
                <dependency>
                    <groupId>org.springframework.cloud</groupId>
                    <artifactId>spring-cloud-dependencies</artifactId>
                    <version>Dalston.SR2</version>
                    <type>pom</type>
                    <scope>import</scope>
                </dependency>
            </dependencies>
        </dependencyManagement>
        <!--编译java版本-->
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                    <configuration>
                        <source>1.8</source>
                        <target>1.8</target>
                        <encoding>UTF-8</encoding>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

      创建 sso-server 认证服务器 pom.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <parent>
            <artifactId>sso-demo</artifactId>
            <groupId>com.imooc.sso</groupId>
            <version>1.0.0-SNAPSHOT</version>
        </parent>
        <modelVersion>4.0.0</modelVersion>
    
        <artifactId>sso-server</artifactId>
    
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-security</artifactId>
            </dependency>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</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>
    
    </project>
    

      

    SsoAuthorizationServerConfig.java
    package com.imooc.sso.server;
    
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    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.TokenStore;
    import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
    import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;
    
    /**
     * @Title: SsoAuthorizationServerConfig
     * @ProjectName ssodemo
     * @date 2021-01-0214:17
     */
    @Configuration
    @EnableAuthorizationServer
    public class SsoAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    
        @Override
        public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    
            clients.inMemory()
                    .withClient("imooc1") // 授权的应用
                    .secret("imoocsecret1")         // 密码
                    .authorizedGrantTypes("authorization_code", "refresh_token")  // 授权的类型
                    .scopes("all") // 范围
                    .autoApprove(true)
                    .and()
                    .withClient("imooc2")
                    .secret("imoocsecret2")
                    .authorizedGrantTypes("authorization_code", "refresh_token")
                    .scopes("all")
                    .autoApprove(true);
    
        }
    
        /**
         * 配置jwt token
         * @return
         */
        @Bean
        public TokenStore jwtTokenStore() {
            return new JwtTokenStore(jwtAccessTokenConvert());
        }
        @Bean
        public JwtAccessTokenConverter jwtAccessTokenConvert() {
            JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
            // jwt token 签名key
            converter.setSigningKey("imooc");
            return converter;
        }
    
        /**
         * 使jwt token 生效
         */
        @Override
        public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
            endpoints.tokenStore(jwtTokenStore()).accessTokenConverter(jwtAccessTokenConvert());
        }
    
        /**
         * 安全配置, 用户访问token Key 的时候 需要身份认证.
         */
        @Override
        public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
            security.tokenKeyAccess("isAuthenticated()");
        }
    }
    

      SsoUserDetailsService.java

    package com.imooc.sso.server;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.security.core.authority.AuthorityUtils;
    import org.springframework.security.core.userdetails.User;
    import org.springframework.security.core.userdetails.UserDetails;
    import org.springframework.security.core.userdetails.UserDetailsService;
    import org.springframework.security.core.userdetails.UsernameNotFoundException;
    import org.springframework.security.crypto.password.PasswordEncoder;
    import org.springframework.stereotype.Component;
    
    /**
     * @Title: SsoUserDetailsService
     * @ProjectName ssodemo
     * @date 2021-01-0215:10
     */
    
    /**
     * 配置用户名密码,不使用配置文件
     */
    @Component
    public class SsoUserDetailsService implements UserDetailsService {
        @Autowired
        private PasswordEncoder passwordEncoder;
        @Override
        public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
            return new User(username, passwordEncoder.encode("123456"),
                    true, true, true, true,
                    AuthorityUtils.commaSeparatedStringToAuthorityList("admin,ROLE_USER"));
        }
    }
    

      

    SsoSecurityConfig.java
    package com.imooc.sso.server;
    
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
    import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
    import org.springframework.security.crypto.password.PasswordEncoder;
    
    /**
     * @Title: SsoSecurityConfig
     * @ProjectName ssodemo
     * @date 2021-01-0215:06
     */
    @Configuration
    public class SsoSecurityConfig extends WebSecurityConfigurerAdapter {
    
    
        @Bean
        public PasswordEncoder passwordEncoder() {
            return new BCryptPasswordEncoder();
        }
    
        @Autowired
        private SsoUserDetailsService ssoUserDetailsService;
    
        /**
         * 配置自己的userDetail 和 密码加密器
         * @param auth
         * @throws Exception
         */
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.userDetailsService(ssoUserDetailsService).passwordEncoder(passwordEncoder());
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .formLogin()  // 表单登录
                .and()
                .authorizeRequests().anyRequest().authenticated();  // 所有请求都需要身份认证
        }
    }
    

    自动提交授权

    SpelView.java
    package com.imooc.sso.server;
    
    import org.springframework.context.expression.MapAccessor;
    import org.springframework.expression.Expression;
    import org.springframework.expression.spel.standard.SpelExpressionParser;
    import org.springframework.expression.spel.support.StandardEvaluationContext;
    import org.springframework.security.oauth2.common.util.RandomValueStringGenerator;
    import org.springframework.util.PropertyPlaceholderHelper;
    import org.springframework.web.servlet.View;
    import org.springframework.web.servlet.support.ServletUriComponentsBuilder;
    
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.util.HashMap;
    import java.util.Map;
    
    /**
     * @Title: SpelView
     * @ProjectName ssodemo
     * @date 2021-01-0215:22
     */
    class SpelView implements View {
    
        private final String template;
    
        private final String prefix;
    
        private final SpelExpressionParser parser = new SpelExpressionParser();
    
        private final StandardEvaluationContext context = new StandardEvaluationContext();
    
        private PropertyPlaceholderHelper.PlaceholderResolver resolver;
    
        public SpelView(String template) {
            this.template = template;
            this.prefix = new RandomValueStringGenerator().generate() + "{";
            this.context.addPropertyAccessor(new MapAccessor());
            this.resolver = new PropertyPlaceholderHelper.PlaceholderResolver() {
                public String resolvePlaceholder(String name) {
                    Expression expression = parser.parseExpression(name);
                    Object value = expression.getValue(context);
                    return value == null ? null : value.toString();
                }
            };
        }
    
        public String getContentType() {
            return "text/html";
        }
    
        public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
                throws Exception {
            Map<String, Object> map = new HashMap<String, Object>(model);
            String path = ServletUriComponentsBuilder.fromContextPath(request).build()
                    .getPath();
            map.put("path", (Object) path==null ? "" : path);
            context.setRootObject(map);
            String maskedTemplate = template.replace("${", prefix);
            PropertyPlaceholderHelper helper = new PropertyPlaceholderHelper(prefix, "}");
            String result = helper.replacePlaceholders(maskedTemplate, resolver);
            result = result.replace(prefix, "${");
            response.setContentType(getContentType());
            response.getWriter().append(result);
        }
    
    }
    

      SsoApprovalEndpoint.java

    package com.imooc.sso.server;
    
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    import org.springframework.web.bind.annotation.SessionAttributes;
    import org.springframework.web.servlet.ModelAndView;
    
    import javax.servlet.http.HttpServletRequest;
    import java.util.Map;
    
    /**
     * @Title: SsoApprovalEndpoint
     * @ProjectName ssodemo
     * @date 2021-01-0215:21
     */
    //@RestController
    //@SessionAttributes("authorizationRequest")
    public class SsoApprovalEndpoint {
    
        @RequestMapping("/oauth/confirm_access")
        public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
            String template = createTemplate(model, request);
            if (request.getAttribute("_csrf") != null) {
                model.put("_csrf", request.getAttribute("_csrf"));
            }
            return new ModelAndView(new SpelView(template), model);
        }
    
        protected String createTemplate(Map<String, Object> model, HttpServletRequest request) {
            String template = TEMPLATE;
            if (model.containsKey("scopes") || request.getAttribute("scopes") != null) {
                template = template.replace("%scopes%", createScopes(model, request)).replace("%denial%", "");
            }
            else {
                template = template.replace("%scopes%", "").replace("%denial%", DENIAL);
            }
            if (model.containsKey("_csrf") || request.getAttribute("_csrf") != null) {
                template = template.replace("%csrf%", CSRF);
            }
            else {
                template = template.replace("%csrf%", "");
            }
            return template;
        }
    
        private CharSequence createScopes(Map<String, Object> model, HttpServletRequest request) {
            StringBuilder builder = new StringBuilder("<ul>");
            @SuppressWarnings("unchecked")
            Map<String, String> scopes = (Map<String, String>) (model.containsKey("scopes") ? model.get("scopes") : request
                    .getAttribute("scopes"));
            for (String scope : scopes.keySet()) {
                String approved = "true".equals(scopes.get(scope)) ? " checked" : "";
                String denied = !"true".equals(scopes.get(scope)) ? " checked" : "";
                String value = SCOPE.replace("%scope%", scope).replace("%key%", scope).replace("%approved%", approved)
                        .replace("%denied%", denied);
                builder.append(value);
            }
            builder.append("</ul>");
            return builder.toString();
        }
    
        private static String CSRF = "<input type='hidden' name='${_csrf.parameterName}' value='${_csrf.token}' />";
    
        private static String DENIAL = "<form id='denialForm' name='denialForm' action='${path}/oauth/authorize' method='post'><input name='user_oauth_approval' value='false' type='hidden'/>%csrf%<label><input name='deny' value='Deny' type='submit'/></label></form>";
    
        private static String TEMPLATE = "<html><body style='display:none;'><h1>OAuth Approval</h1>"
                + "<p>Do you authorize '${authorizationRequest.clientId}' to access your protected resources?</p>"
                + "<form id='confirmationForm' name='confirmationForm' action='${path}/oauth/authorize' method='post'><input name='user_oauth_approval' value='true' type='hidden'/>%csrf%%scopes%<label><input name='authorize' value='Authorize' type='submit'/></label></form>"
                + "%denial%</body><script>document.getElementById('confirmationForm').submit()</script></html>";
    
        private static String SCOPE = "<li><div class='form-group'>%scope%: <input type='radio' name='%key%'"
                + " value='true'%approved%>Approve</input> <input type='radio' name='%key%' value='false'%denied%>Deny</input></div></li>";
    
    }
    

      application.properties

    server.port=9999
    server.context-path= /server
    #security.user.password= 123456
    

     创建 sso-client1 项目

    SsoClient1Application.java

    package com.imooc.sso.client;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
    import org.springframework.security.core.Authentication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Title: SsoClient1Application
     * @ProjectName ssodemo
     * @date 2021-01-0214:37
     */
    
    @SpringBootApplication
    @RestController
    @EnableOAuth2Sso
    public class SsoClient1Application {
        public static void main(String[] args) {
            SpringApplication.run(SsoClient1Application.class, args);
        }
    
        @GetMapping("/user")
        public Authentication user(Authentication user) {
            return user;
        }
    }
    

    application.properties

    security.oauth2.client.clientId=imooc1
    security.oauth2.client.clientSecret=imoocsecret1
    # 需要授权时,跳转认证服务器,获取授权码
    security.oauth2.client.user-authorization-uri=http://127.0.0.1:9999/server/oauth/authorize
    # 携带授权码请求令牌
    security.oauth2.client.access-token-uri=http://127.0.0.1:9999/server/oauth/token
    # 获取jwt秘钥 (获取秘钥也需要认证,所以会携带 clientId和clientSecret)
    security.oauth2.resource.jwt.key-uri=http://127.0.0.1:9999/server/oauth/token_key
    
    server.port=8080
    server.context-path=/client1
    

    resources/static/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Client1</title>
    </head>
    <body>
     <h1>SSO Demo client1 </h1>
     <a href="http://127.0.0.1:8060/client2/index.html">访问Client2</a>
    </body>
    </html>
    
     创建 sso-client2 项目
    SsoClient2Application.java
    package com.imooc.sso.client;
    
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.autoconfigure.security.oauth2.client.EnableOAuth2Sso;
    import org.springframework.security.core.Authentication;
    import org.springframework.web.bind.annotation.GetMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    /**
     * @Title: SsoClient1Application
     * @ProjectName ssodemo
     * @date 2021-01-0214:37
     */
    
    @SpringBootApplication
    @RestController
    @EnableOAuth2Sso
    public class SsoClient2Application {
        public static void main(String[] args) {
            SpringApplication.run(SsoClient2Application.class, args);
        }
    
        @GetMapping("/user")
        public Authentication user(Authentication user) {
            return user;
        }
    }
    

     application.properties 

    security.oauth2.client.clientId=imooc2
    security.oauth2.client.clientSecret=imoocsecret2
    # 需要授权时,跳转认证服务器,获取授权码
    security.oauth2.client.user-authorization-uri=http://127.0.0.1:9999/server/oauth/authorize
    # 携带授权码请求令牌
    security.oauth2.client.access-token-uri=http://127.0.0.1:9999/server/oauth/token
    # 获取jwt秘钥 (获取秘钥也需要认证,所以会携带 clientId和clientSecret)
    security.oauth2.resource.jwt.key-uri=http://127.0.0.1:9999/server/oauth/token_key
    
    server.port=8060
    server.context-path=/client2
    

      resources/static/index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Client2</title>
    </head>
    <body>
     <h1>SSO Demo client2 </h1>
     <a href="http://127.0.0.1:8080/client1/index.html">访问Client1</a>
    </body>
    </html>
    

      

    
    
  • 相关阅读:
    android studio 汉化 个性化 美化 快速操作项目 目录
    Where should we fork this repository?
    剑指offer-链表中环的入口节点
    剑指offer-两个链表的第一个公共节点
    剑指offer-链表中倒数第k个结点
    算法导论-快速排序
    剑指offer-旋转数组的最小数字
    剑指offer-数组中出现次数超过一半的数字
    PAT1048. Find Coins(01背包问题动态规划解法)
    17网易-优雅的点
  • 原文地址:https://www.cnblogs.com/412013cl/p/14223672.html
Copyright © 2020-2023  润新知