Spring Cloud security combat service _5-2_ micro authorization code to achieve certification process

The current architecture

So far, has achieved the separation of the former back-end architecture, micro-environment service, a complete business logic, including user login, access tokens, holding the token transfer service, quit. (Procedure follows)

The current framework is, there are some problems:

1, the user enters a user name and password, is submitted to a front-end server, the front-end server developers, will come into contact with the user's username and password, security problems

2. Each client application needs to handle the login logic, once logged logic changes, all clients must be changed, re-deployment, there are coupling.

Desired scene

 When users need to log on, the front-end server directly to the user guide to the authentication server, the action is completed on the authentication server.

The advantage of this is:

1, the client application is completely out of the reach username and password of the user to ensure security.

2, the client application is not logged logic, login logic on the authentication server, the login logic if there is a change, the authentication server directly modify a reduced coupling.

Modify the program to the top of the framework (authorization code pattern OAuth protocol)

+++++++++++++++++++++++ special episode, speak some OAuth protocol of four kinds authorization model ++++++++++++++++ ++++++++

1, the password mode

Before licensing model also has been used for a scene: the phone app, this is a client application that you can trust that your app is developed by his company. But this model is not suitable for use in the web scene in web, user name and password are not directly write their own applications to fill, but fill a page on the browser rendered, the browser is a client application of a proxy, the browser is unable to guarantee security. (Still not quite understand where insecurity)

 

 

 2, the authorization code pattern

 

1, the user access to the client application

2, guide the user to the authentication server to log on (this step is required to carry clientId client application can be forwarded directly html authentication server), user name, password

3, after successful authentication, the authentication server applications send an authorization code to the client code

4, the client application holding the authorization code code, and clientId, clientSecret, in exchange for access_token

5, returned to the client application access_token 

这种场景下,用户名、密码、客户端应用信息,都没有直接暴露在浏览器,是web下是最安全的。

3,隐式授权/简化授权

 

 

 

 

授权码模式的简化,用户认证成功后,直接将token返回给浏览器。因为某些应用没有前端服务器,只有一堆静态的html(很少见),这种模式,一般不用。

4,客户端证书

 

 

 客户端应用直接发 clientId、clientSecret给认证服务器,发的令牌是针对客户端应用的,不是针对用户的。跟没授权一样,令牌不能识别用户身份。

+++++++++++++++++++++++++++++++++我是分割线结束+++++++++++++++++++++++++++++++++++++++++

 改造nb-admin代码为授权码模式

1,删掉登录页面,登录是在认证服务器上完成的,所以这里删除nb-admin的登录页面

2,进入 index.html,点击登录,将用户引导到认证服务器提供的登录页去。

 index.html:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Index</title>
</head>
<body>
    <h1>welcome to 系统1</h1>
    <div id="loginTip"></div>
    <p><button onclick="getOrderInfo()">获取订单信息</button></p>

    <table>
        <tr><td>order id</td><td><input id="orderId" /></td></tr>
        <tr><td>order product id</td><td><input id="productId" /></td></tr>
    </table>




</body>
<script src="http://libs.baidu.com/jquery/2.0.0/jquery.min.js"></script>
<script>

    function getOrderInfo(){
        $.get("api/order/orders/1",function(data){
            $("#orderId").val(data.id);
            $("#productId").val(data.productId);
        });
    }

    $(document).ready(function(){

        $.get("/me",function(data,status){
            if(data){
                //已登录
                var htm = "已登录,<a href='/logout'>退出</a>";
                $("#loginTip").html(htm);
            }else{
                //未登录
                var href = "<a href='/toAuthLogin'>未登录,去登录</a>";
                $("#loginTip").append(href);
            }
        });
    });

</script>
</html>

点击登录按钮,转发到认证服务器,这个可以放在前端做,因为只有clientId信息,没有安全问题。

/**
     * 重定向到认证服务器的登录页
     * @param response
     * @throws IOException
     */
    @GetMapping("/toAuthLogin")
    public void toAuthLogin(HttpServletResponse response) throws IOException{

        String redirectUrl = "http://auth.nb.com:9090/oauth/authorize?"
                            +"client_id=admin&"
                            +"redirect_uri=http://admin.nb.com:8080/oauth/callback&"
                            +"response_type=code&"
                            +"state=/index"; //state参数传过去啥传回来啥,一般记录跳转之前的路径
        response.sendRedirect(redirectUrl);
    }

授权回调:

/**
     * 授权回调
     * @param code 授权码
     * @param state 自定义参数
     * @param session
     */
    @GetMapping("/oauth/callback")
    public String callback(@RequestParam String code,String state ,HttpSession session){

        log.info("code is {}, state is {}",code,state);

        //认证服务器验token地址 /oauth/check_token 是  spring .security.oauth2的验token端点
        String oauthServiceUrl = "http://gateway.nb.com:9070/token/oauth/token";

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);//不是json请求
        //网关的appId,appSecret,需要在数据库oauth_client_details注册
        headers.setBasicAuth("admin","123456");

        MultiValueMap<String,String> params = new LinkedMultiValueMap<>();
        params.add("code",code);//授权码
        params.add("grant_type","authorization_code");//授权类型-授权码模式
        //认证服务器会对比数据库客户端信息的的redirect_uri和这里的是不是一致,不一致就报错
        params.add("redirect_uri","http://admin.nb.com:8080/oauth/callback");

        HttpEntity<MultiValueMap<String,String>> entity = new HttpEntity<>(params,headers);
        ResponseEntity<AccessToken> response = restTemplate.exchange(oauthServiceUrl, HttpMethod.POST, entity, AccessToken.class);

        session.setAttribute("token",response.getBody());

        return "redirect:/index";
    }

给admin应用添加授权码模式:

 

 启动admin服务,认证服务,订单服务,网关,访问admin

 

 点击去登录,跳转到了认证服务器,这是自带的页面

 

可以重写认证服务器的安全配置方法,自定义登录页

 

 

 

 到目前为止已经完成了上述授权码授权流程,但是还存在很多问题,比如,现在的退出登录:

@GetMapping("/logout")
    public String logout(HttpSession session){
        session.invalidate();
        return "index";
    }

只是将nb-admin客户端应用的session失效调了,里面没有token了,但是认证服务器上的token并没有失效,再点击登录,直接就会登录成功,不用输入用户名密码,给人的感觉是“没有退出去”。

下节来处理这些问题,本节代码github:https://github.com/lhy1234/springcloud-security/tree/chapt-5-2-authcode

 

Guess you like

Origin www.cnblogs.com/lihaoyang/p/12142861.html