微服务从零开始之登录与注册一

�概述

任何一个微服务需要基本的安全保证, 也是遵循AAA原则: 鉴证,授权和计帐

  • Authentication 要求是合法用户
  • Authorization 要求有合法权限
  • Accounting 要求有记录可追踪

让我们从需求分析到代码实现,尽量啰嗦地来说说怎么做一个看似简单的登录注册模块, 假设该服务叫做 Checklist 我的清单

需求分析

用例 Use case

除了使用绘图工具和画用例图, 还有有�几种方法通过脚本来�生成用例图

一是使用在线网站 yuml.me

https://yuml.me/608ca377

微服务从零开始之登录与注册一_第1张图片
use case

UML 生成脚本如下

[User]-(Sign In)
[User]-(Sign Out)
[User]-(Sign Up)
[User]-(Forget Password)
[User]-(Change Password)
(Sign In)>(Remember Me)
(Sign Up)>(Send Verification Email)
(Forget Password)>(Send Reset Password Email)
(Change Password)<(Send Reset Password Email)
[Admin]^[User]
[Admin]-(Add User)
[Admin]-(Delete User)
[Admin]-(Lock User)
[Admin]-(Change Password Policy)

�二是使用是通过 plantuml 来生成

到 http://plantuml.com/ 上下载 plantuml.jar , 然后用如下命令生成用例图

java -jar plantuml.jar usecase.txt

示例UML 生成脚本如下

@startuml

User -> (Sign In)
User --> (Sign Out) 
User --> (Sign Up)
User --> (activate)
User --> (forget/reset password)
:Admin: ---> (lock user)
:Admin: ---> (add user) 
:Admin: ---> (delete user) 

@enduml

三是使用graphviz

先安装graphviz, 再运行如下命令

dot usecase1.gv -Tpng -o usecase1.png

示例UML生成脚本如下

digraph G {
    rankdir=LR;

    subgraph clusterUser {label="User"; labelloc="b"; peripheries=0; user};
    
    user [shapefile="stick.png", peripheries=0];

    signin [label="Sign In", shape=ellipse];

    signout [label="Sign Out", shape=ellipse];

    signup [label="Sign Up", shape=ellipse];

    user->signin [arrowhead=none];

    user->signout [arrowhead=none];

    user->signup [arrowhead=none];
}

用户故事 User Story

User Story 讲究 INVEST 原则

  • "I" ndependent (of all others) 独立的
  • "N" egotiable (not a specific contract for features) 可协商的
  • "V" aluable (or vertical) 有价值的
  • "E" stimable (to a good approximation) 可估量的
  • "S" mall (so as to fit within an iteration) 足够小的
  • "T" estable (in principle, even if there isn't a test for it yet) 可测试的

Sign Up 注册

  1. 作为一个未注册用户, 我想输入我的电子邮件地址和密码,注册到 Checklist
    1.1 我必须输入合法和邮件地址,符合密码策略的密码以及一致的验证码进行注册
    默认的密码策略是最低8个字符, �必须包含大小写字母和至少一个数字

| # | Story | Priority | Estimation | Deadline| Comments |
|---|---|---|---|---|
| 1.1.1 | �生成验证码 |---|---|---|--- |
| 1.1.2 | 显示注册表单|---|---|---|--- |
| 1.1.3 | 邮件地址格式验证|---|---|---|--- |
| 1.1.4 | 比较两次输入的密码是否相同|---|---|---|--- |
| 1.1.5 | 验证密码是否符合密码策略|---|---|---|--- |
| 1.1.6 | 验证输入的验证码|---|---|---|--- |
| 1.1.7 | 检查是否已有相同的邮件地址存在|---|---|---|--- |
| 1.1.8 | 输入验证无误后存入数据库,状态为pending|---|---|---|--- |
| 1.1.9 | 生成此用户的激活链接|---|---|---|--- |
| 1.1.10 | 向注册邮箱发送一封确认邮件|---|---|---|--- |

1.2 我的注册邮箱会收到一封验证邮件, 提示我点击注册连接, �从而激活我的注册帐户

1.3 当我完成激活后会自动跳到 Checklist 的首页, 提示我进行登录

实现

这次我们用Java实现,选择的框架是Spring Boot, 先从最笨最直接的方法入手, 之后再看看相关的框架 Spring Security 和 Apache Shiro 是怎么做的

Model

微服务从零开始之登录与注册一_第2张图片
model

View

字段 �控件
username text
email email
password password
confirmPassword password
rememberMe checkbox
forgetPassword link

创建项目

  • 在 http://start.spring.io 上选择所需模块, 创建 Checklist 项目并打包下载
微服务从零开始之登录与注册一_第3张图片
spring boot starter

或者直接用 Spring Cli 直接生成

spring init --build=maven --java-version=1.8 --dependencies=web --packaging=jar --groupId=com.github.walterfan --artifactId=checklist

在实践中始终牢记 三个基本点

  • 无模型不编程-MDD 模型驱动开发
  • 无测试不开发-TDD 测试驱动开发
  • 无度量不交付-MDD 度量驱动开发

领域模型很简单
Register
User
Role

测试用例也简单

  1. 注册
  2. 激活
  3. 登录

度量就只记录

  1. 注册次数
  2. 激活次数
  3. 性能数据

代码结构

废话不多说,上代码 checklist source codes on github

微服务从零开始之登录与注册一_第4张图片
code structure

数据库我们选用两个

  1. h2 作为测试数据库
               
            com.h2database
            h2
            runtime
        
  1. mysql 作为产品数据库
                 
            mysql
            mysql-connector-java
            5.1.41
        

表现层

表现层选用 Freemarker 作为后端模板, 前端选用 AngularJS + BootStrap

freemarker 是比较流行的后端页面生成的模板引擎, 这所以不用 JSP 和 JSF, 就是为了不想在后端模板层面引入太多逻辑和不必要的复杂性, freemarker 就只干模板引擎该干的事

在 src/main/resources/templates 做如下模板

  • about.ftl
  • admin.ftl
  • footer.ftl
  • header.ftl
  • index.ftl
  • layout.ftl
  • login.ftl

主要的 Freemarker 模板 layout.ftl 如下

<#macro myLayout>



    
    
    
    
    
    
    

    Check List

    
    

    
    

    
    
    
    

    
    
    
    
    

    

    





<#include "header.ftl"/>
<#nested/>
<#include "footer.ftl"/>

首页

微服务从零开始之登录与注册一_第5张图片
home page

源码 index.ftl 如下

<#import "layout.ftl" as layout>
<@layout.myLayout>

Checklist

Checklist for your work and life

Add a Check list

微服务从零开始之登录与注册一_第6张图片
login page

登录页面

微服务从零开始之登录与注册一_第7张图片
register page

源码 login.ftl 如下

<#import "layout.ftl" as layout>
<@layout.myLayout>



注: 我不太擅长前端页面的界面设计, 这里参考了 http://bootsnipp.com/snippets/jvgVX 的示例, 一个很有用的基于 bootstrap 的样式主题设计网站

当用户点击注册页面, 填写所需字段, 并提交表单时, 用 Angular JS 向后台提交, 代码如下

'use strict';

$(function() {

    $('#login-form-link').click(function(e) {
        $("#login-form").delay(100).fadeIn(100);
        $("#register-form").fadeOut(100);
        $('#register-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });
    $('#register-form-link').click(function(e) {
        $("#register-form").delay(100).fadeIn(100);
        $("#login-form").fadeOut(100);
        $('#login-form-link').removeClass('active');
        $(this).addClass('active');
        e.preventDefault();
    });

});

// Defining angularjs application.
var myApp = angular.module('myApp', []);
// Controller function and passing $http service and $scope var.
myApp.controller('myController', function($scope, $http) {
    // create a blank object to handle form data.
    $scope.user = {};
    // calling our submit function.
    $scope.submitRegisterForm = function() {
        var postData = {
            username:$scope.user.username,
            email: $scope.user.email,
            password: $scope.user.password,
            passwordConfirmation: $scope.user.passwordConfirmation
        };
        $http({
            method  : 'POST',
            url     : '/checklist/api/v1/users/register',
            data    : postData,
            headers : {'Content-Type': 'application/json'}
        })
            .success(function(data) {
                if (data.errors) {
                    // Showing errors.
                    $scope.errors = data.errors;
                } else {
                    $scope.message = data.message;
                }
            });
    };

    $scope.submitLoginrForm = function() {
        var postData = {
            email: $scope.user.email,
            password: $scope.user.password,
        };
        $http({
            method  : 'POST',
            url     : '/checklist/api/v1/users/login',
            data    : postData,
            headers : {'Content-Type': 'application/json'}
        })
            .success(function(data) {
                if (data.errors) {
                    // Showing errors.
                    $scope.errors = data.errors;
                } else {
                    $scope.message = data.message;
                }
            });
    };
});

好了表现层包括前端的代码大致搞定了, 现在开始写后端的 Java web service 代码, 参见 微服务从零开始之登录与注册二

你可能感兴趣的:(微服务从零开始之登录与注册一)