zoukankan      html  css  js  c++  java
  • cowboy添加验证码

    参考的http://beebole.com/blog/erlang/how-to-implement-captcha-in-erlang-web-application/,移到cowboy,修改了下;废话不多说,直接贴代码

    注意,需要cowboy版本1.0.1

    需要imagemagick

    sudo apt-get install imagemagick

    mac

    brew install imagemagick

    mac下如果使用convert命令找不到字体,则需要安装下这个

    brew install ghostscript

    创建工程

    rebar-creator create-app testCaptcha

    testCaptcha_app

    -module(testCaptcha_app).
    
    -behaviour(application).
    
    -export([start/2, stop/1]).
    
    -define(C_ACCEPTORS,  100).
    
    start(_StartType, _StartArgs) ->
    
        simple_captcha_ets:init(),
    
        application:start(crypto),
        application:start(cowlib),
        application:start(ranch),
        application:start(cowboy),
    
        Routes    = route_helper:get_routes(),
        Dispatch  = cowboy_router:compile(Routes),
        Port      = 8080,
        TransOpts = [{port, Port}],
        ProtoOpts = [{env, [{dispatch, Dispatch}]}],
        cowboy:start_http(http, ?C_ACCEPTORS, TransOpts, ProtoOpts).
    
    stop(_State) ->
        simple_captcha_ets:destroy(),
        ok.


    route_helper
    -module(route_helper).
    
    -export([get_routes/0]).
    
    get_routes() ->
        [
            {'_', [
                {"/captcha", captcha_handler, []},
                {"/captcha_check", captcha_check_handler, []}
            ]}
        ].
    
    

    simple_captcha
    -module(simple_captcha).
    
    -export([create/0,check/2]).
    
    create() ->
        CryptKey  = mochihex:to_hex(crypto:rand_bytes(16)),
        Code = generate_rand(5),
    
        FileName = lists:flatmap(fun(Item) -> integer_to_list(Item) end, tuple_to_list(now())),
        File = io_lib:format("/tmp/~s.png",[FileName]),
    
        Cmd = io_lib:format("convert -background 'none' -fill '#222222' -size 175 -gravity Center -wave 5x100 -swirl 50 -font DejaVu-Serif-Book -pointsize 28 label:~s -draw 'Bezier 10,40 50,35 100,35 150,35 200,50 250,35 300,35' ~s", [Code, File]),
        os:cmd(Cmd),
    
        {ok, BinPng} = file:read_file(File),
        file:delete(File),
    
        simple_captcha_ets:insert(Code,CryptKey),
    
        {erlang:list_to_bitstring(CryptKey),BinPng}.
    
    check(CryptKeyBitString,CodeBitString) ->
        CryptKey = erlang:bitstring_to_list(CryptKeyBitString),
        Code = erlang:bitstring_to_list(CodeBitString),
        CryptKeyFromEts = simple_captcha_ets:find(Code),
    
        case string:equal(CryptKeyFromEts,CryptKey) of
            true ->
                simple_captcha_ets:remove(code),
                true;
            _ ->
                false
        end.
    
    
    %private
    generate_rand(Length) ->
        Now = now(),
        random:seed(element(1, Now), element(2, Now), element(3, Now)),
        lists:foldl(fun(_I, Acc) -> [do_rand(0) | Acc] end, [], lists:seq(1, Length)).
    
    do_rand(R) when R > 46, R < 58; R > 64, R < 91; R > 96 ->  
        R;
    
    do_rand(_R) ->
        do_rand(47 + random:uniform(75)).
    simple_captcha_ets
    -module(simple_captcha_ets).
    
    -export([init/0,insert/2,find/1,remove/1,destroy/0]).
    
    init()->
      TableName = ets:new(simple_captcha, [public,named_table]),
      {ok, TableName}.
    
    insert(Key,Value) ->
      ets:insert(simple_captcha, {Key, Value}),
      ok.
    
    find(Key) ->
      Result = (
          try ets:lookup_element(simple_captcha, Key, 2) of
            Value ->
              Value
          catch
            _:_ ->
              ""
          end
      ),
      Result.
    
    remove(Key) ->
      try ets:delete(simple_captcha, Key)
      catch
        _:_ ->
          ok
      end.
    
    destroy()->
      try ets:delete(simple_captcha)
      catch
        _:_ ->
          ok
      end.
    mochihex
    自己下载
    captcha_handler
    -module(captcha_handler).
    
    -export([init/3]).
    -export([handle/2]).
    -export([terminate/3]).
    
    init(_Transport, Req, []) ->
      {ok, Req, undefined}.
    
    handle(Req, State) ->
      %CryptKey用于验证的时候用,需本地保存,CapCode为用户提交的数据
      %simple_captcha:check(CryptKey, CapCode)
      {CryptKey,BinPng} =  simple_captcha:create(),
    
      Req2 = cowboy_req:set_resp_cookie(<<"cap">>, CryptKey, [{path, <<"/">>}], Req),
      {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"image/png">>}],BinPng, Req2),
      {ok, Req3, State}.
    
    terminate(_Reason, _Req, _State) ->
      ok.
    captcha_check_handler
    -module(captcha_check_handler).
    
    -export([init/3]).
    -export([handle/2]).
    -export([terminate/3]).
    
    init(_Transport, Req, []) ->
      {ok, Req, undefined}.
    
    handle(Req, State) ->
      {CryptKey,_} = cowboy_req:cookie(<<"cap">>, Req,<<"">>),
      {ok, PostVals, Req2} = cowboy_req:body_qs(Req),
      CaptchaCode = proplists:get_value(<<"captchaCode">>, PostVals),
    
      case simple_captcha:check(CryptKey, CaptchaCode) of
        true ->
          {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"text/html">>}],<<"ok">>, Req2),
          {ok, Req3, State};
        _ ->
          {ok, Req3} = cowboy_req:reply(200, [{<<"content-type">>, <<"text/html">>}],<<"error">>, Req2),
          {ok, Req3, State}
      end.
    
    terminate(_Reason, _Req, _State) ->
      ok.

    rebar.config

    % -*- erlang -*-
    {erl_opts, [debug_info]}.
    {deps, [
      {cowboy,".*", {git, "https://github.com/ninenines/cowboy", {tag,"1.0.1"}}}
    ]}.
    {cover_enabled, true}.
    
    {eunit_opts, [verbose, {report,{eunit_surefire,[{dir,"."}]}}]}.
    {sub_dirs, ["apps/testCaptcha", "rel"]}.

    run.sh

    #!/bin/sh
    rebar clean;
    rebar compile;
    erl -pa apps/*/ebin deps/*/ebin -eval "application:start(testCaptcha)."

    captcha_test.html

    <img src="http://127.0.0.1:8080/captcha" width="100" height="100">
    
    <form action="http://127.0.0.1:8080/captcha_check" method="post">
      <p>captcha<input type="text" name="captchaCode" /></p>
      <input type="submit" value="Submit" />
    </form>

     收工

  • 相关阅读:
    所有蚂蚁掉下来前的最后一刻
    最长有效括号
    n的第k个因子--leetcode1492
    删掉一个元素以后全为1的最长子数组。
    public class和class的区别
    数据库中的乐观锁和悲观锁以及实现方式
    HashMap底层实现原理 扩容机制
    jvm 内存泄漏现象和处理方案
    Django模板标签语法
    Django图片的上传与下载
  • 原文地址:https://www.cnblogs.com/ziyouchutuwenwu/p/4424499.html
Copyright © 2011-2022 走看看