当前位置:   article > 正文

Spring Security Oauth2 授权码模式下 自定义登录、授权页面_oauth2自定义界面自定义登录接口实现授权

oauth2自定义界面自定义登录接口实现授权

主要说明:基于若依springcloud微服务框架的2.1版本

嫌弃缩进不舒服的,直接访问我的博客站点:
http://binarydance.top//aticle_view.html?aticle_id=603216759344082944&t=1623984554005
一开始网上教程一堆,都是各抄各的,有的直接代码缺少,有的直接不可以用(MLGB的),于是乎去spring官网找找看,还真找到,最终自己配置搭建成功跑了一遍demo,美滋滋。一些HTML文件还是网上的,见谅~

由于是springcloud项目(注册和配置中心是nacos),认证中心在auth模块,自己demo搭建测试直接在auth模块,没有走网关gateway

目前测试的scope只有一个:server,见表:sys_oauth_client_details

sys_oauth_client_details表:

CREATE TABLE `sys_oauth_client_details` (
  `client_id` varchar(255) NOT NULL COMMENT '终端编号',
  `resource_ids` varchar(255) DEFAULT NULL COMMENT '资源ID标识',
  `client_secret` varchar(255) NOT NULL COMMENT '终端安全码',
  `scope` varchar(255) NOT NULL COMMENT '终端授权范围',
  `authorized_grant_types` varchar(255) NOT NULL COMMENT '终端授权类型',
  `web_server_redirect_uri` varchar(255) DEFAULT NULL COMMENT '服务器回调地址',
  `authorities` varchar(255) DEFAULT NULL COMMENT '访问资源所需权限',
  `access_token_validity` int(11) DEFAULT NULL COMMENT '设定终端的access_token的有效时间值(秒)',
  `refresh_token_validity` int(11) DEFAULT NULL COMMENT '设定终端的refresh_token的有效时间值(秒)',
  `additional_information` varchar(4096) DEFAULT NULL COMMENT '附加信息',
  `autoapprove` tinyint(4) DEFAULT NULL COMMENT '是否登录时跳过授权',
  `origin_secret` varchar(255) NOT NULL COMMENT '终端明文安全码',
  PRIMARY KEY (`client_id`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC COMMENT='终端配置表';
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
INSERT INTO `sys_oauth_client_details` VALUES ('web', '', '$2a$10$t.Hw9Nu.lWp5iK9I7MZRCuX9EeV2DNu6xj9wunfD5ZclvQSdoBo5O', 'server', 'password,refresh_token,authorization_code,implicit,client_credentials', 'https://www.baidu.com', NULL, 604800, 1209600, NULL, NULL, '123456');
  • 1

Spring Security Oauth2 的maven坐标:

    <!-- Spring Security Oauth2 -->
    <dependency>
        <groupId>org.springframework.cloud</groupId>
        <artifactId>spring-cloud-starter-oauth2</artifactId>
        <version>2.2.1.RELEASE</version>
    </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

项目配置:

# Tomcat
server: 
  port: 9200

# Spring
spring: 
  application:
    # 应用名称
    name: my-auth
  profiles:
    # 环境配置
    active: dev
  cloud:
    nacos:
      discovery:
        # 服务注册地址
        server-addr: 192.168.1.39:8848
      config:
        # 配置中心地址
        server-addr: 192.168.1.39:8848
        # 配置文件格式
        file-extension: yml
        # 共享配置
        shared-configs: application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
  main: 
     allow-bean-definition-overriding: 
       true
     
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

引入模板解析引擎:

        <!-- thymeleaf 模板引擎-->
		<dependency>
		    <groupId>org.springframework.boot</groupId>
		    <artifactId>spring-boot-starter-thymeleaf</artifactId>
		</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

AuthorizationServerConfigurerAdapter无需改动,你的是什么就是什么:

@Configuration
@EnableAuthorizationServer
@Slf4j
public class AuthServerConfig extends AuthorizationServerConfigurerAdapter {
// 无需改动,你的是什么就是什么
......
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

上面是基础,关键来了:
resources下面建立static目录,放置登录页面(注意:form表单action="/login"):base-login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
</head>
 
<style>
    .login-container {
        margin: 50px;
        width: 100%;
    }
 
    .form-container {
        margin: 0px auto;
        width: 50%;
        text-align: center;
        box-shadow: 1px 1px 10px #888888;
        height: 300px;
        padding: 5px;
    }
 
    input {
        margin-top: 10px;
        width: 350px;
        height: 30px;
        border-radius: 3px;
        border: 1px #E9686B solid;
        padding-left: 2px;
 
    }
 
 
    .btn {
        width: 350px;
        height: 35px;
        line-height: 35px;
        cursor: pointer;
        margin-top: 20px;
        border-radius: 3px;
        background-color: #E9686B;
        color: white;
        border: none;
        font-size: 15px;
    }
 
    .title{
        margin-top: 5px;
        font-size: 18px;
        color: #E9686B;
    }
</style>
<body>
<div class="login-container">
    <div class="form-container">       
        <form class="form-signin" method="post" action="/login">
	        <h2 class="form-signin-heading">用户登录</h2>
	        <p>
	          <label for="username" class="sr-only">用户名</label>
	          <input type="text" id="username" name="username" class="form-control" placeholder="用户名" required autofocus>
	        </p>
	        <p>
	          <label for="password" class="sr-only">密码</label>
	          <input type="password" id="password" name="password" class="form-control" placeholder="密码" required>
	        </p>
	        <button class="btn btn-lg btn-primary btn-block" type="submit">&nbsp;&nbsp;</button>
	      </form>
    </div>
</div>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

配置WebSecurityConfigurerAdapter:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
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;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * Security 安全认证相关配置
 */
@Order(99)
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
    
    /**
     * 配置修改hideUserNotFoundExceptions = false,不隐藏usernameNotFundExceptions
     * @return
     */
    @Bean
    public DaoAuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setHideUserNotFoundExceptions(false);
        provider.setUserDetailsService(userDetailsService);
        provider.setPasswordEncoder(passwordEncoder());
        return provider;
    }
    
    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider());
    }  
    
    @Override
    protected void configure(HttpSecurity http) throws Exception { 
         http
                 .formLogin()
                 .loginPage("/base-login.html") //自定义的登录页面 **重要**
                 .loginProcessingUrl("/login")  //原始的处理登录的URL,保持和base-login.html的form表单的action一致 **重要**
                 .permitAll() //放开 **重要**
                 .and()
                 .requestMatchers().antMatchers("/oauth/**","/login/**","/logout/**")// **重要**
                 .and()
                 .authorizeRequests()   
	             .antMatchers(
	               "/xxx/**",).permitAll()//一些需要放开的URL
                 .anyRequest().authenticated()
	             .and().headers().frameOptions().disable()
	             .and().csrf().disable();
                 
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76

到此登录页面自定义完成。别急,还有自定义授权页面呢。

在resources目录下面建立templates目录,放置授权页面(注意:form表单action="/oauth/authorize"):base-grant.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>授权</title>
</head>
<style>
 
    html{
        padding: 0px;
        margin: 0px;
    }
 
    .title {
        background-color: #E9686B;
        height: 50px;
        padding-left: 20%;
        padding-right: 20%;
        color: white;
        line-height: 50px;
        font-size: 18px;
    }
    .title-left{
        float: right;
    }
    .title-right{
        float: left;
    }
    .title-left a{
        color: white;
    }
    .container{
        clear: both;
        text-align: center;
    }
    .btn {
        width: 350px;
        height: 35px;
        line-height: 35px;
        cursor: pointer;
        margin-top: 20px;
        border-radius: 3px;
        background-color: #E9686B;
        color: white;
        border: none;
        font-size: 15px;
    }
</style>
<body style="margin: 0px">
<div class="title">
    <div class="title-right">oauth2授权</div>
    <div class="title-left">
        <a href="#help">帮助</a>
    </div>
</div>
    <div class="container">
         <h3 th:text="${clientId}+' 请求授权,该应用将获取你的以下信息'"></h3>
        <p>昵称,头像和性别</p>
         授权后表明你已同意 <a  href="#boot" style="color: #E9686B">服务协议</a>
        <form method="post" action="/oauth/authorize">
            <input type="hidden" name="user_oauth_approval" value="true">
             <div th:each="item:${scopes}">
                <input type="radio" th:name="'scope.'+${item}" value="true" checked>同意 
		        <input type="radio" th:name="'scope.'+${item}" value="false" >拒绝
             </div>
           <input name="authorize" value="同意/授权" type="submit">
        </form>
        
    </div>
</body>
</html>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71

同时,controller覆盖oauth2的方法:

import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.springframework.security.oauth2.provider.AuthorizationRequest;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.servlet.ModelAndView;

@Controller
//必须配置
@SessionAttributes("authorizationRequest")
public class BootGrantController {

 @RequestMapping("/oauth/confirm_access")
 public ModelAndView getAccessConfirmation(Map<String, Object> model, HttpServletRequest request) throws Exception {
     AuthorizationRequest authorizationRequest = (AuthorizationRequest) model.get("authorizationRequest");
     ModelAndView view = new ModelAndView();
     view.setViewName("base-grant"); //自定义页面名字,resources\templates\base-grant.html
     view.addObject("clientId", authorizationRequest.getClientId());
     view.addObject("scopes",authorizationRequest.getScope());
     return view;
 }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26

在这里插入图片描述

至此,自定义登录页面、授权页面完成。

①获取授权码code(注意:client_id=web):

http://192.168.1.39:9200/oauth/authorize?response_type=code&client_id=web&redirect_uri=https://www.baidu.com&scope=server
  • 1

第一次访问上面地址获取授权码code,先会跳转至自定义登录页面:
在这里插入图片描述

输入账号密码,跳转至授权页面:
在这里插入图片描述

同意之后,跳转到我们设定的redirect_uri=https://www.baidu.com,同时获取授权码code(牛逼,这样图片也违规,去我博客站点看吧~):
在这里插入图片描述
②根据上面获取的授权码code=rLePQ8获取访问的token:
在这里插入图片描述
至此流程完成,等到我们的token
③根据token去访问你需要的资源吧。

特别说明的是:第一次授权以后获取授权码code,之后获取授权码code直接收入账号、密码后立即返回授权码code,并不会再一次要求用户进入授权页面(base-grant.html)允许、拒绝选择操作。

如果希望默认就是授权,不需要跳出授权页面(base-grant.html),那么sys_oauth_client_details表中,autoapprove(是否登录时跳过授权)设置为true(值:1)即可。

Spring Security Oauth2 授权码模式下 自定义登录、授权页面(演示)

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/84259
推荐阅读
相关标签
  

闽ICP备14008679号