Spring Security(六):认证(Authentication)-Web社交登录(Social)-QQ

QQ第三方登录文档 http://wiki.connect.qq.com/

一:成为个人开发者

1. 在QQ互联(https://connect.qq.com)上称为个人开发者,填上一些基本信息

  • 名称: 自己的身份证上的姓名
  • 联系地址:自己实际居住的地址
  • 手机号码:自己的手机号
  • 电子邮箱:自己的邮箱,申请开发者时会收到一封确认邮件"腾讯开放平台-开发者注册认证",点击一下链接就可以了
  • 身份证号码:自己的身份证号码
  • 照片:自己拿着身份证,并且身份证中的照片要在人的右边,具体如下图
    在这里插入图片描述
    信息都填完了,点击 提交审核,等待审核结果。

二:创建网站应用

创建网站应用时需要一个已经备过案的域名,可以通过IPC备案查询网站(http://icp.chinaz.com/) 查询域名的具体信息。如果自己没有备过案的域名,可以暂时使用公司的域名,这好像对公司没啥影响。如果没有公司域名,那就在网上随意找个域名,然后在IPC备案查询网站中查询一下该网站的具体信息,用别人的域名。如果用公司的或者别人的域名自己开发好功能了,删除掉应用,避免影响到别的公司,其实也没啥影响。

  • 基本信息
    • 网站名称 :通过 IPC备案查询网站查询的域名上会有网站名称,填写查询出来的名称
    • 网站类别 :自己访问以下那个备案的网站,看一下该网站是什么类型的,然后选择一下
    • 网站简介:随便写一下该网站的功能
    • 网站logo:去网站上应该能找到相应的图片,下载下来,然后修改图片的大小100X100
  • 平台信息
    • 网站地址 :备案的域名,如http://www.example.com/
    • 网站回调域: 备案域名的子路径,如http://www.example.com/social/callback 这个地址在第三方登录时会使用到,可以随便写,后面也可以随意修改
    • 主办单位名称:在IPC备案查询网站中输入备案的域名可以查询出来
    • 网站备案号:在IPC备案查询网站中输入备案的域名可以查询出来

三:社交登录原理

在这里插入图片描述
在这里插入图片描述

四:Spring Security接入

在这里插入图片描述

1. 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>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.5.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example.security</groupId>
    <artifactId>springboot-security-social</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>springboot-security-social</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>org.thymeleaf.extras</groupId>
            <artifactId>thymeleaf-extras-springsecurity5</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-web</artifactId>
            <version>1.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-core</artifactId>
            <version>1.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-config</artifactId>
            <version>1.1.4.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.social</groupId>
            <artifactId>spring-social-security</artifactId>
            <version>1.1.4.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.0.14.RELEASE</version>
        </dependency>

        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.2</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.6</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.51</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>
</project>

2. AbstractOAuth2ApiBinding

调用QQ第三方的api获取用户的信息

public interface QQ {
    QQUserInfo getUserInfo();
}
@Data
@ToString
@RequiredArgsConstructor
public class QQUserInfo {
    /**
     * 	返回码
     */
    private String ret;
    /**
     * 如果ret<0,会有相应的错误信息提示,返回数据全部用UTF-8编码。
     */
    private String msg;
    /**
     *
     */
    private String openId;
    /**
     * 不知道什么东西,文档上没写,但是实际api返回里有。
     */
    private String is_lost;
    /**
     * 省(直辖市)
     */
    private String province;
    /**
     * 市(直辖市区)
     */
    private String city;
    /**
     * 出生年月
     */
    private String year;
    /**
     * 	用户在QQ空间的昵称。
     */
    private String nickname;
    /**
     * 	大小为30×30像素的QQ空间头像URL。
     */
    private String figureurl;
    /**
     * 	大小为50×50像素的QQ空间头像URL。
     */
    private String figureurl_1;
    /**
     * 	大小为100×100像素的QQ空间头像URL。
     */
    private String figureurl_2;
    /**
     * 	大小为40×40像素的QQ头像URL。
     */
    private String figureurl_qq_1;
    /**
     * 	大小为100×100像素的QQ头像URL。需要注意,不是所有的用户都拥有QQ的100×100的头像,但40×40像素则是一定会有。
     */
    private String figureurl_qq_2;
    /**
     * 	性别。 如果获取不到则默认返回”男”
     */
    private String gender;
    /**
     * 	标识用户是否为黄钻用户(0:不是;1:是)。
     */
    private String is_yellow_vip;
    /**
     * 	标识用户是否为黄钻用户(0:不是;1:是)
     */
    private String vip;
    /**
     * 	黄钻等级
     */
    private String yellow_vip_level;
    /**
     * 	黄钻等级
     */
    private String level;
    /**
     * 标识是否为年费黄钻用户(0:不是; 1:是)
     */
    private String is_yellow_year_vip;
}
public class QQImpl extends AbstractOAuth2ApiBinding implements QQ {

    private static final String URL_GET_OPENID = "https://graph.qq.com/oauth2.0/me?access_token=%s";
    private static final String URL_GET_USERINFO = "https://graph.qq.com/user/get_user_info?oauth_consumer_key=%s&openid=%s";

    private String appId;
    private String openId;

    private ObjectMapper objectMapper = new ObjectMapper();

    public QQImpl(String accessToken, String appId) {
        super(accessToken, TokenStrategy.ACCESS_TOKEN_PARAMETER);
        this.appId = appId;

        String url = String.format(URL_GET_OPENID, accessToken);
        // callback( {"client_id":"xxx","openid":"xxxx"} );
        String result = getRestTemplate().getForObject(url, String.class);
        System.out.println(result);
        String[] items = result.split("openid");
        String openid = items[1].substring(3, items[1].length() - 6);
        this.openId = openid;
    }
    /**
     * QQ 互联
     * https://connect.qq.com/ 文档资料 Api文档/Api列表/访问用户资料(get_user_info)
     * @return
     */
    public QQUserInfo getUserInfo() {
        String url = String.format(URL_GET_USERINFO, appId, openId);
        String result = getRestTemplate().getForObject(url, String.class);
        System.out.println(result);
        QQUserInfo userInfo = JSONObject.parseObject(result, QQUserInfo.class);
        userInfo.setOpenId(openId);

        return userInfo;
    }
}

3. OAuth2Template

调用api发送请求的模板

public class QQOAuth2Template extends OAuth2Template {

    public QQOAuth2Template(String clientId, String clientSecret, String authorizeUrl, String accessTokenUrl) {
        super(clientId, clientSecret, authorizeUrl, accessTokenUrl);
        setUseParametersForClientAuthentication(true);
    }

    @Override
    protected RestTemplate createRestTemplate() {
        RestTemplate restTemplate = super.createRestTemplate();
        restTemplate.getMessageConverters().add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
        return restTemplate;
    }

    @Override
    protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap<String, String> parameters) {
        // access_token=xxx&expires_in=7776000&refresh_token=xxx
        String responseString = getRestTemplate().postForObject(accessTokenUrl, parameters, String.class);
        String[] items = responseString.split("&");
        String accessToken = items[0].split("=")[1];
        Long expiresIn = new Long(items[1].split("=")[1]);
        String refreshToen = items[2].split("=")[1];


        return new AccessGrant(accessToken, null, refreshToen, expiresIn);
    }
}

4. ApiAdapter

public class QQAdapter implements ApiAdapter<QQ> {
    @Override
    public boolean test(QQ qq) {
        return true;
    }

    @Override
    public void setConnectionValues(QQ qq, ConnectionValues values) {
        QQUserInfo userInfo = qq.getUserInfo();
        values.setDisplayName(userInfo.getNickname());
        values.setImageUrl(userInfo.getFigureurl_qq_1());
        values.setProfileUrl(null);
        values.setProviderUserId(userInfo.getOpenId());
    }

    @Override
    public UserProfile fetchUserProfile(QQ qq) {
        return null;
    }

    @Override
    public void updateStatus(QQ qq, String s) {

    }
}

5. QQServiceProvider

public class QQServiceProvider extends AbstractOAuth2ServiceProvider<QQ> {

    private String appId;

    private static final String URL_AUTHORIZE = "https://graph.qq.com/oauth2.0/authorize";
    private static final String URL_ACCESS_TOKEN = "https://graph.qq.com/oauth2.0/token";

    public QQServiceProvider(String appId, String appSecret) {
        super(new QQOAuth2Template(appId, appSecret, URL_AUTHORIZE, URL_ACCESS_TOKEN));
        this.appId = appId;
    }

    @Override
    public QQ getApi(String accessToken) {
        return new QQImpl(accessToken, appId);
    }
}

6. OAuth2ConnectionFactory

public class QQConnectionFactory extends OAuth2ConnectionFactory<QQ> {
    public QQConnectionFactory(String providerId, String appId, String appSecret) {
        super(providerId, new QQServiceProvider(appId, appSecret), new QQAdapter());
    }
}

7. SocialConfiguration

@Data
@ConfigurationProperties(prefix = "social.qq")
public class QQProperties {
    private String filterProcessesUrl = "/auth";
    private String providerId = "qq";
    private String appId;
    private String appSecret;
    private String signupUrl;
}

application.yml
注意:

  • appId和appSecret要使用自己创建的应用对应的值。
  • filterProcessesUrl和providerId 要和创建应用时网站回调域的子路径保持一致,即 如果网站回调域为http://www.example.com/qqLogin/callback.do,那么filterProcessesUrl为/qqLogin,而providerId为callback.do,关于网站回调域的子路径可以任意修改,修改这个值不需要QQ互联重新审核。
server:
  port: 8080

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/test?useUnicode=true&characterEncoding=utf8
    driver-class-name: com.mysql.cj.jdbc.Driver
    username: root
    password: root123

social:
  qq:
    appId: xxx
    appSecret: xxx
    filterProcessesUrl: /qqLogin
    providerId: callback.do
    signupUrl: /signup

ConnectionSignUp: 当第三方登录授权成功后跳转到signup页面,用于走注册流程或者完善账号信息流程(如手机号等信息)

@Component
public class MyConnecitonSignUp implements ConnectionSignUp {
    @Override
    public String execute(Connection<?> connection) {
        // 根据社交用于信息默认创建用户并返回用户的唯一标识
        return connection.getDisplayName();
    }
}
public class MySpringSocialConfigurer extends SpringSocialConfigurer {

    private String filterProcessesUrl;

    public MySpringSocialConfigurer(String filterProcessesUrl) {
        this.filterProcessesUrl = filterProcessesUrl;
    }

    @Override
    protected <T> T postProcess(T object) {
        SocialAuthenticationFilter filter = (SocialAuthenticationFilter) super.postProcess(object);
        filter.setFilterProcessesUrl(filterProcessesUrl);
        return (T) filter;
    }
}

注意:需要手动的先建好表,建表sql在 spring-social-core-1.1.4.RELEASE.jar/org/springframework/social/connect/jdbc/JdbcUsersConnectionRepository.sql

@Configuration
@EnableSocial
public class SocialConfiguration extends SocialConfigurerAdapter {

    @Autowired
    private DataSource dataSource;

    @Autowired
    private QQProperties properties;

    @Autowired
    private MyConnecitonSignUp myConnecitonSignUp;

    /**
     * 建表 spring-social-core-1.1.4.RELEASE.jar/org/springframework/social/connect/jdbc/JdbcUsersConnectionRepository.sql
     *
     * create table UserConnection (userId varchar(255) not null,
     * 	providerId varchar(255) not null,
     * 	providerUserId varchar(255),
     * 	rank int not null,
     * 	displayName varchar(255),
     * 	profileUrl varchar(512),
     * 	imageUrl varchar(512),
     * 	accessToken varchar(512) not null,
     * 	secret varchar(512),
     * 	refreshToken varchar(512),
     * 	expireTime bigint,
     * 	primary key (userId, providerId, providerUserId));
     * create unique index UserConnectionRank on UserConnection(userId, providerId, rank);
     * @param connectionFactoryLocator
     * @return
     */
    @Override
    public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
        // Encryptors.noOpText() 对数据不加密
        JdbcUsersConnectionRepository jdbcUsersConnectionRepository = new JdbcUsersConnectionRepository(dataSource, connectionFactoryLocator, Encryptors.noOpText());
        // 只能设置表前缀,但是不能修改表名
        jdbcUsersConnectionRepository.setTablePrefix("");
        if (myConnecitonSignUp != null) {
            jdbcUsersConnectionRepository.setConnectionSignUp(myConnecitonSignUp);
        }
        return jdbcUsersConnectionRepository;
    }

    @Bean
    public MySpringSocialConfigurer mySpringSocialConfigurer() {
        MySpringSocialConfigurer springSocialConfigurer = new MySpringSocialConfigurer(properties.getFilterProcessesUrl());
        springSocialConfigurer.userIdSource(getUserIdSource());
        springSocialConfigurer.signupUrl(properties.getSignupUrl());
        return springSocialConfigurer;
    }

    @Override
    public UserIdSource getUserIdSource() {
        return new AuthenticationNameUserIdSource();
    }

    @Bean
    public ProviderSignInUtils providerSignInUtils(ConnectionFactoryLocator connectionFactoryLocator) {
        return new ProviderSignInUtils(connectionFactoryLocator, getUsersConnectionRepository(connectionFactoryLocator));
    }
}
@Configuration
@ConditionalOnProperty(prefix = "social.qq", name = "appId")
@EnableConfigurationProperties(QQProperties.class)
public class QQAutoConfig extends SocialConfigurerAdapter {

    @Autowired
    private QQProperties properties;

    protected ConnectionFactory<?> createConnectionFactory() {
        return new QQConnectionFactory(properties.getProviderId(), properties.getAppId(), properties.getAppSecret());
    }

    @Override
    public void addConnectionFactories(ConnectionFactoryConfigurer configurer, Environment environment) {
        configurer.addConnectionFactory(this.createConnectionFactory());
    }

    @Override
    public UsersConnectionRepository getUsersConnectionRepository(ConnectionFactoryLocator connectionFactoryLocator) {
        return null;
    }
}

8. UserDetailsService

@Data
@ToString
@AllArgsConstructor
@RequiredArgsConstructor
public class SysPermission implements GrantedAuthority {
    private Long id;
    private String name;
    private String code;
    private String url;
    private String method;

    /**
     * 次方法很重要,用于唯一标识一个权限
     * @return
     */
    @Override
    public String getAuthority() {
        return "ROLE_" + this.code + ":" + this.method.toUpperCase();
    }
}
@Data
@ToString
@AllArgsConstructor
@RequiredArgsConstructor
public class SysUser {
    private Long id;
    private String username;
    private String password;

    private List<SysPermission> sysPermissions;
}
@Component
public class MyUserDetailsService implements UserDetailsService, SocialUserDetailsService {
    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 根据用户名查询用户信息和权限
        SysUser user = queryUserInfo(username, null);
        if (user == null) {
            throw new UsernameNotFoundException(username);
        }

        return new User(user.getUsername(), user.getPassword(), user.getSysPermissions());
    }

    @Override
    public SocialUserDetails loadUserByUserId(String userId) throws UsernameNotFoundException {
        // 根据用户名查询用户信息和权限
        SysUser user = queryUserInfo(null, userId);
        if (user == null) {
            throw new UsernameNotFoundException(userId);
        }

        return new SocialUser(userId, user.getPassword(), true, true, true, true, user.getSysPermissions());
    }
    
    public SysUser queryUserInfo(String username, String userId) {
        SysUser user = new SysUser(1L, "admin", "$2a$10$nm5H9QvnoWao.l7NbxQGZeZoR0Cn.VqCpsl3E/FhglPa954Zg9ccm", Arrays.asList(
                new SysPermission(1L, "用户列表", "user:view", "/getUserList", "GET"),
                new SysPermission(2L, "添加用户", "user:add", "/addUser", "POST"),
                new SysPermission(3L, "修改用户", "user:update", "/updateUser", "PUT")
        ));
        
        return user;
    }

    public static void main(String[] args) {
        System.out.println(new BCryptPasswordEncoder().encode("123456"));
    }
}

9. SecurityConfiguration

@Slf4j
@Component
public class MyAuthenticationSuccessHandler implements AuthenticationSuccessHandler {

    @Autowired
    private ObjectMapper objectMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        log.info("login sucesssful {}", objectMapper.writeValueAsString(authentication));

        response.sendRedirect("/index");
    }
}
@Slf4j
@Component
public class MyAuthenticationFailureHandler implements AuthenticationFailureHandler {
    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
      log.info("认证失败");
      response.setContentType("text/html;charset=utf-8");
      response.getWriter().write(exception.getMessage());
    }
}
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;

    @Autowired
    private MyAuthenticationSuccessHandler myAuthenticationSuccessHandler;

    @Autowired
    private MyAuthenticationFailureHandler myAuthenticationFailureHandler;

    @Autowired
    private MySpringSocialConfigurer mySpringSocialConfigurer;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
                .apply(mySpringSocialConfigurer).and()
                // 配置需要认证的请求
                .authorizeRequests()
                .antMatchers("/login", "/signup", "/user/regist").permitAll()
                .anyRequest()
                    .authenticated()
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .successHandler(myAuthenticationSuccessHandler)
                    .failureHandler(myAuthenticationFailureHandler)
                    .failureUrl("/login?error")
                    .permitAll()
                    .and()
                .logout()
                    .permitAll();

    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

}

10. UserController

@Data
public class SocialUserInfo {
    private String providerId;
    private String providerUserId;
    private String nickname;
    private String headimg;
}
@RestController
public class UserController {

    @Autowired
    private ProviderSignInUtils providerSignInUtils;

    @GetMapping("/user/me")
    public String me() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        return auth.toString();
    }

    @GetMapping("/social/user")
    public SocialUserInfo getSocialUserInfo(HttpServletRequest request) {
        SocialUserInfo userInfo = new SocialUserInfo();
        Connection<?> connection = providerSignInUtils.getConnectionFromSession(new ServletWebRequest(request));
        userInfo.setProviderId(connection.getKey().getProviderId());
        userInfo.setNickname(connection.getDisplayName());
        userInfo.setHeadimg(connection.getImageUrl());
        return userInfo;
    }

    @PostMapping("/user/regist")
    public void regist(SysUser user, HttpServletRequest request) {
        String userId = user.getUsername();
        providerSignInUtils.doPostSignUp(userId, new ServletWebRequest(request));
    }
}
@Configuration
public class WebMvcConfiguration implements WebMvcConfigurer {

    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/login").setViewName("login");
        registry.addViewController("/signup").setViewName("signup");
        registry.addViewController("/index").setViewName("index");
    }
}

11. html

login.html

注意:<a href="/qqLogin/callback.do">QQ登录</a>QQ登录的href地址为application.yml中的flterProcessesUrl和providerId的值的拼接在一起的子路径。

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8">
    <title>登录</title>
</head>
<body>
<a href="/qqLogin/callback.do">QQ登录</a>
</body>
</html>

signup.html

<!DOCTYPE html>
<html lang="en"
      xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="utf-8">
    <title>注册</title>
</head>
<body>
<form method="post" action="/user/regist">
    <h2 class="form-signin-heading">注册</h2>
    <p>
        <label for="username">用户名</label>
        <input type="text" id="username" name="username" required autofocus>
    </p>
    <p>
        <label for="password">密码</label>
        <input type="password" id="password" name="password" required>
    </p>
    <button type="submit" name="type" value="regist">注册</button>
    <button type="submit" name="type" value="binding">绑定</button>
</form>
</body>
</html>

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<head>
    <meta charset="utf-8">
</head>
<body>
<h1>首页</h1>
登录名:<span sec:authentication="name"></span>
</body>
</html>

五:服务器配置

1. 配置hosts文件

vi /etc/hosts

# 这里的www.example.com为创建应用是填的网站地址对应的域名
127.0.0.1 www.example.com

2. nginx配置

主要是server配置,将80端口映射到8080端口上。QQ认证是会有个回调地址redirect_uri,这个地址默认会使用80端口,而我们的应用程序一般为其它端口,所以需要将80端口映射成8080端口。

注意在启用nginx时看一下80端口是否被占用了,像mac开机就会启动apache httpd就是用的80端口,需要将其停掉。查找80端口是否被占用命令 sudo lsof -n -P | grep :80

# 启动nginx
sudo nginx -c /usr/local/etc/nginx/nginx.conf
user root staff;
worker_processes  1;

#error_log  logs/error.log;
#error_log  logs/error.log  notice;
#error_log  logs/error.log  info;

pid        logs/nginx.pid;


events {
    worker_connections  1024;
}


http {
    include       mime.types;
    default_type  application/octet-stream;

    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /usr/local/etc/nginx/logs/host.access.log  main;

    sendfile        on;
    #tcp_nopush     on;

    #keepalive_timeout  0;
    keepalive_timeout  65;

    gzip  on;

    server {
        listen       80;
        server_name  www.example.com;

        set $doc_root /usr/local/var/www;

        location / {
            proxy_pass http://www.example.com:8080;
        }

        location ^~ /images/ {
            root $doc_root;
        }

        location ~ .(gif|jpg|jpeg|png|bmp|ico|swf|css|js)$ {
           root $doc_root/img;
        }
     }


    include servers/*;
}

访问登录页面使用域名来访问,如 http://www.example.com/login,登录成功进入到index.html

注意创建应用时的网站回调域的值要必须和QQ认证页面中的https://graph.qq.com/oauth2.0/show?redirect_uri=http://www.examole.com:8080/qqLogin/callback.do中的redirect_uri值要完全一致,这里不知道为什么redirect_uri中域名把8080端口给我带出来了,为了保持一致,我在配置网站回调域的时候也要把端口8080加上,这样才能保持完全一致。即网站回调域配置为http://www.examole.com:8080/qqLogin/callback.do

在这里插入图片描述
在这里插入图片描述

GitHub源码地址:https://github.com/mengday/springboot-security-social

发布了308 篇原创文章 · 获赞 936 · 访问量 133万+

猜你喜欢

转载自blog.csdn.net/vbirdbest/article/details/90740279