[Grails]限制網站可以接受的Domain name

現在很多服務會建立domain name導向你的ip
會讓你的網站被他的網址綁架

不知道這樣做的實際用途,考量到安全問題,可以在Grails Filter加上檢查機制
只要不是你接受的Domain Name,自動導向你要的網站

參考程式碼

//此範例可以將網站導向正確網址(利用人家的page ranking)
// 也可以送出403 error
// ((HttpServletResponse) response).sendError(403);
if (!(request.getServerName().equals("你可以接受的網址")) {
  response.setHeader("Location", "你想要導向的網址");
  response.status = 301;
  response.flushBuffer();
  return false;
} else {
  //正常呼叫
}

Android : Swipe View With Tabs

分成三個步驟


1.在onCreate時候建立ActionBar,ActionBar.addTab增加Tab的頁面,並且在FragmentActivity實作TabListener


2.建立一個class繼承FragmentStatePagerAdapter用來狀載Fragment頁面


3.實作TabListener後要orverride OnTabSelected

public class PaymentInfoActivity extends FragmentActivity implements
  TabListener {

 CollectionPagerAdapter mPagerAdapter;
 ViewPager mViewPager;

 @Override 
protected void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 setContentView(R.layout.activity_payment_info);

 final ActionBar mActionBar = getActionBar();
 mActionBar.setHomeButtonEnabled(true);
 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
 mViewPager = (ViewPager) findViewById(R.id.pager);
 if (mViewPager != null) {
         mPagerAdapter = new CollectionPagerAdapter(
  getSupportFragmentManager());
  mViewPager.setAdapter(mPagerAdapter);
  mViewPager.setOnPageChangeListener(new ViewPager
                                        .SimpleOnPageChangeListener() {

     @Override
     public void onPageSelected(int position) {
  mActionBar.setSelectedNavigationItem(position);
     }
  });
 }
 TextView view1 = (TextView) getLayoutInflater().inflate(
   R.layout.view_custom_tab, null);
 view1.setText(mPagerAdapter.getPageTitle(0));
 mActionBar.addTab(mActionBar.newTab().setCustomView(view1)
   .setTabListener(this));
 TextView view2 = (TextView) getLayoutInflater().inflate(
   R.layout.view_custom_tab, null);
 view2.setText(mPagerAdapter.getPageTitle(1));
 mActionBar.addTab(mActionBar.newTab().setCustomView(view2)
   .setTabListener(this));
    }
}
  
 class CollectionPagerAdapter extends FragmentStatePagerAdapter {

  public CollectionPagerAdapter(FragmentManager fm) {
   super(fm);
  }

  @Override
  public Fragment getItem(int position) {
   switch (position) {
   case 0:
    return new PaymentPickupFragment();
   case 1:
    return new PaymentSearchFragment();
   }
   return null;
  }

   String[] title = new String[] {getResources().getString(R.string.web_payment),
     getResources().getString(R.string.search_payment) };

  @Override
  public CharSequence getPageTitle(int position) {

   return title[position];
  }

  @Override
  public int getCount() {
   // TODO Auto-generated method stub
   return 2;
  }

 }
 @Override
 public void onTabSelected(Tab tab, FragmentTransaction ft) {
  mViewPager.setCurrentItem(tab.getPosition());
 }


FragmentActivity的xml

     
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

<android.support.v4.view.ViewPager
    android:id="@+id/pager"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >
</RelativeLayout>

最後要記得建立多個Fragment頁面加入Tab

在Synology安裝Piwigo相簿軟體

在Synology安裝Piwigo相簿很簡單,只要按照以下步驟(假設已經開啟Synology資料庫與Web 伺服器功能)

1.新增要給Piwigo使用的資料庫
2.到Piwigo下載完整的程式壓縮檔
3.解壓縮到你的網站伺服器資料夾(假設 piwigo)
4.連線到你的piwigo網址(假設 http://my_server_ip/piwigo)
5.根據提示連入你的資料庫帳號密碼與相關資料即可

但是如果你是裝在synology上面,因為synology預設只有裝gd,但piwigo可以使用imagick跟gd,且預設會自動先找imagick,所以在安裝完成後,圖片上傳是無法進行轉換的。

這時候必須去修改piwigoincludeconfig_default.inc.php裡面去找到

$conf[‘graphics_library’] = ‘auto’;

然後把它改成

$conf[‘graphics_library’] = ‘gd’;

然後就可以開始使用Piwigo了

Ubuntu 設定 Apache + Tomcat + SSL 憑證

因為開發的網站牽涉到金流問題,因此必須使用https安全通道來傳送資料,原本主機上就有Apache Web Server走80 port,以及Apacha Tomcat走8080 port,但是當一遇到要走https後狀況就變複雜了,因為在Apache Web Server是443 port,而Tomcat是8443 port,原本使用ProxyPass將http 80 port轉到Tomcat 8080 port的方法似乎不能同理用在https上。解決方式是必須透過Apache VirtualHost的SSL設定,並使用ajp的方式轉換到Tomcat上。

1.安裝 OpenSSL
sudo apt-get install openssl

2.啟用SSL
sudo a2enmod ssl
(如果要停用 sudo a2dismod ssl)

3.安裝憑證
這一步驟先教大家產生自己的私人憑證,壞處是當你用https連線時,瀏覽器會出現警告訊息,這是因為憑證沒有經過第三方公司認證過,最好的作法就是去購買一個已經認證過的憑證或是使用StartSSL的免費憑證服務(https://www.startssl.com/),這部份可以參考(http://blog.mowd.tw/index.php?pl=950)
3.1.建立憑證目錄
sudo mkdir /etc/apache2/ssl
3.2.產生憑證
openssl req -new -x509 -days 365 -nodes -out /etc/apache2/ssl/apache.pem -keyout /etc/apache2/ssl/apache.key
(-days 後面的參數365是憑證的有效日期,可以依需要自行調整,-out 和 –keyout 是憑證和金鑰產出後要存放的路徑。)

4.修改虛擬主機設定
這一段是原本80 port透過ajp轉到tomcat的設定
<VirtualHost *:80>
ProxyPreserveHost On
ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
ServerName 127.0.0.1
</VirtualHost>


這一段則是將https轉到tomcat的https且不用轉到tomcat:8443的port
<VirtualHost *:443>
SSLEngine on
#使用自己產生的憑證
SSLCertificateFile /etc/apache2/ssl/apache.pem
SSLCertificateKeyFile /etc/apache2/ssl/apache.key
#以下設定是使用StartSSL產生的檔案用
#SSLCertificateFile /etc/apache2/ssl/ssl.crt
#SSLCertificateKeyFile /etc/apache2/ssl/ssl.key
#SSLCertificateChainFile /etc/apache2/ssl/sub.class1.server.ca.pem
#SSLCACertificateFile /etc/apache2/ssl/ca.pem

ProxyPass / ajp://localhost:8009/
ProxyPassReverse / ajp://localhost:8009/
ServerName 127.0.0.1

</VirtualHost>

如此一來就可以同時使用http與https透過apache來轉址到tomcat上
5.重新啟動apache

[Grails]在Tomcat環境下使用ssl憑證配置

為了網站的訊息傳輸安全性,尤其是當涉及金流、線上刷卡的服務時,一般網站會使用加密的HTTP(也就是HTTPS)來傳輸資料,如此一來就可以防止中間人竊取資料,這篇文章簡單的介紹一下在Grails+Tomcat+Linux環境下,如何建立設定HTTPS的環境。

主要步驟如下:
1.產生憑證金鑰(.keystore)
2.複製金鑰到Tomcat目錄
3.設定Tomcat的server.xml
4.修改Grails應用程式的web.xml設定

以下詳細描述各步驟

1.產生憑證金鑰(.keystore)

因為是要給Tomcat使用的金鑰,所以這裡就使用Java內建的keytool工具
在命令列下輸入以下指令keytool -genkey”
然後跟著指示依序輸入以下資料:
輸入 keystore 密碼:
重新輸入新密碼:
您的名字與姓氏為何?
  [Unknown]:
您的編制單位名稱為何?
  [Unknown]:  
您的組織名稱為何?
  [Unknown]:
您所在的城市或地區名稱為何?
  [Unknown]: 
您所在的州及省份名稱為何?
  [Unknown]:  
該單位的二字國碼為何
  [Unknown]:
CN=Test, OU=Unknown , O=Unknown , L=Hsinchu, ST=Taiwan, C=Unknown 正確嗎?
  [否]:  Y

輸入 <mykey> 的主密碼
        (RETURN 如果和 keystore 密碼相同):
重新輸入新密碼:

其中比較重要的是密碼部分,這個密碼會在後面Tomcat設定時用到

2.複製金鑰到Tomcat目錄

完成上述步驟後,會產生.keystore檔案,將該檔案複製到tomcat/webapps目錄下

3.設定Tomcat的server.xml

開啟tomcatconfigserver.xml,將以下這段程式碼打開,並且加上keystoreFile與keystorePass兩個屬性後儲存即可,需要重新啟動tomcat才可以讓設定生效

<Connector port="8443″ protocol="HTTP/1.1″ SSLEnabled="true"
 maxThreads="150″  scheme="https" secure="true"
 clientAuth="false" sslProtocol="TLS" keystoreFile="webapps/.keystore"
 keystorePass="[密碼]" />

4.修改Grails應用程式的web.xml設定

要在Grails專案裡面設定web.xml,需先要執行grails install-templates指令,將web.xml取出後,手動設定安全連線的部份,執行指令後會在/src/templates/war/目錄下產生web.xml檔案,開啟該檔案後,新增以下設定資料:

<security-constraint>
<web-resource-collection>
<http-method>GET</http-method>
<http-method>POST</http-method>
<url-pattern>/*</url-pattern>
</web-resource-collection>
<user-data-constraint>
<transport-guarantee>CONFIDENTIAL</transport-guarantee>
</user-data-constraint>
</security-constraint>

之後產生war檔後deploy到tomcat就算完成了。

可以輸入以下網址驗證https是否成功
https://localhost:8443/PROJECT 或是輸入 http://localhost:8080/PROJECT

不過因為憑證是自己建立,所以第一次進到網站的使用者,都會出現以下畫面,必須要按同意繼續,才可以瀏覽網站,為了解決這問題可以透過購買憑證的方式來解決,這部份等試出在在與大家分享。

有興趣者,可以先考慮以下文章

[筆記] SSL 憑證購買記
添加 GoDaddy SSL 证书到你的网站

[Grails]整合TinyMCE與解決UrlMapping路徑問題

TinyMCE是一個可以跨平台,以JavaScript+HTML為基礎開發的所見即所得(WYSIWYG)編輯器,這次整合的目的是客戶希望可以一個類似編輯Word的工具來編輯網站的內容,而不是單純的只有textarea文字。

原本常用的Grails Plugin: RichUI Plugin,裡面也有整合TinyMCE,不過使用起來似乎插入表格會出現問題,且只有整合到3.0版(TinyMCE目前版本4.0b3),因此就考慮不透過richui,直接整合TinyMCE。

步驟如下
1.到官網下載最新的程式碼,把js放到你專案web-appjs下

2.設定顯示頁面
在你想要顯示的頁面include tinymce.min.js

<script src="${resource( dir:’js/tinymce’,file:’tinymce.min.js’)}"></script>

並貼上以下初始設定(詳細可以參考官網)

  • 其中selector指的是你要顯示元件的類型(textarea)與名稱(這裡使用description)
  • 設定你需要的大小(width/height)
  • 預設所有的選項都是英文的,如果需要其他語系可以到這裡下載,不過沒有繁體中文的檔案,可以從我這裡下載,下載後更名為zh_TW.js放在lang目錄下就可以

<script>
tinymce.init({
    selector: “textarea#description",
    theme: “modern",
    width: 600,
    height: 400,
    language:"zh_TW",
    plugins: [
         “advlist autolink link image lists charmap print preview hr anchor pagebreak spellchecker",
         “searchreplace wordcount visualblocks visualchars code fullscreen insertdatetime media nonbreaking",
         “save table contextmenu directionality emoticons template paste textcolor"
   ],
   content_css: “css/content.css",
   toolbar: “insertfile undo redo | styleselect | bold italic | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | l      ink image | print preview media fullpage | forecolor backcolor emoticons", 
   style_formats: [
        {title: ‘Bold text’, inline: ‘b’},
        {title: ‘Red text’, inline: ‘span’, styles: {color: ‘#ff0000’}},
        {title: ‘Red header’, block: ‘h1’, styles: {color: ‘#ff0000’}},
        {title: ‘Example 1’, inline: ‘span’, classes: ‘example1’},
        {title: ‘Example 2’, inline: ‘span’, classes: ‘example2’},
        {title: ‘Table styles’},
        {title: ‘Table row 1’, selector: ‘tr’, classes: ‘tablerow1’}
    ]
 }); 
</script>

3.排除resource轉址
因為TinyMCE會include到其他的js檔案,在Grails會把resource檔案mapping到/static/xxx.js的路徑,會造成其他檔案無法載入,這時候需要在Config.groovy加上以下這一段即可。

grails.resources.adhoc.excludes = [‘/js/tinymce/**/*.*’]

4.大功告成

[Grails]整合Facebook登入機制oAuth

先前介紹了很多Spring Security Core Plugin的用法,在Spring Security Core Plugin的頁面中有提到相當多的Plugin是架構在Spring Security基礎上的,包括Facebook、Twitter、OpenID等。這篇文章將更進階的將Facebook登入與Spring Security Core機制做一個整合。

其實如果網站單純要用某個oAuth的認證方式的話,建議是直接可以參考官方的API直接開發就可以,但是如果跟我一樣需要兼容Spring Security來做登入與頁面權限的管理,用人家開發好的Plugin真的省事很多。

這個套件目前算是還有在更新,不過不知道為什麼評價不是很高,至少有達到我基本的要求就好,細部的不方便就不管了。

在使用這個套件前,務必先安裝好Spring Security Core Plugin,可以參考之前的文章:Grails+Spring Security Core Plugin(Part1) ,裝好以後要做到產生SysUser/SysRole的步驟。

#01#安裝套件
在BuildConfig.groovy裡面加上以下這段

plugins {
        compile “org.grails.plugins:spring-security-facebook:0.11″
}

//說明裡面是0.11版本,但是實際上是0.14.2,我還是用0.11來做

#02#設定Facebook App
https://developers.facebook.com/新增一個App(應用程式)
輸入方便識別的應用程式名稱以及小寫英文的程式名稱空間

選擇以 [Facebook 登入網站]這個項目,設定網站位址

(如果你是在本機開發,可能只有localhost,但是FB並不接受localhost or 127.0.0.1,所以還是要用一個domain name,如果沒有的話隨便設定一個,然後去改你本機的hosts設定,參考這裡)

如果設定完成後,你就可以看到你接下來需要用到的App ID跟App Secret

#03#新增FacebookUser
需要新增一個FacebookUser來儲存該FB的ID與aceesToken,並且跟現有的SpringSecurity User做關連,這裡我以xervice.Member來做例子。

long uid

String accessToken
Date accessTokenExpires
static belongsTo = [user: SysUser]

以上四個屬性是必要的,其中static belongsTo = [user: SysUser]中的SysUser則需看你的SpringSecurity 設定而決定。

class Member {

/* Default (injected) attributes of GORM */

String aboutMe
Date birthday
boolean gender
String email
boolean emailConfirm
String firstName
String lastName
long uid
String accessToken
Date accessTokenExpires
static belongsTo = [user: SysUser]


    static mapping = {
autoTimestamp true
aboutMe type: ‘text’
    }
    
static constraints = {
email (email: true,nullable:true,blank:true)
firstName(blank: true,nullable: true)
lastName(blank: true,nullable: true)
aboutMe(blank: true,nullable: true)
birthday(nullable: true)
uid(unique: true)
    }

}

#04#設定Facebook Plugin
網站上面是建議直接打grails s2-init-facebook //configure Spring Security Facebook
但是好像有點問題,其實直接去改Config.groovy就可以

grails.plugins.springsecurity.facebook.domain.classname=’xervice.Member’
grails.plugins.springsecurity.facebook.appId=’你的APP ID’
grails.plugins.springsecurity.facebook.secret=’你的APP Secret’

#05#設定登入/登出按鈕

因為這個plugin預設幫你新增一個Spring Security User做關連,同時assign ROLE_USER與ROLE_FACEBOOK,因此可以結合Spring Security 的TagLib來做登入登出機制的判斷。
<sec:ifNotGranted roles="ROLE_USER">
  <facebookAuth:connect />
</sec:ifNotGranted>
<sec:ifAllGranted roles="ROLE_USER">
  Welcome <sec:username/>! (<g:link uri="/j_spring_security_logout">Logout</g:link>)
</sec:ifAllGranted>

如此一來就大功告成了,不過離實際的需求可能還是有點出入,還好這個plugin保留不少客製化的空間可以修改。

#06#客製化-設定存取其他資料
這個plugin預設只會去存取該使用者在Facebook的user id,如果需要存取其他資料,則需要在Config.groovy設定

grails.plugins.springsecurity.facebook.permissions = ’email,user_about_me,user_birthday’

其他設定可以參考這裡
https://developers.facebook.com/docs/reference/login/#permissions
http://splix.github.io/grails-spring-security-facebook/guide/single.html#3.1%20Basic%20Usage

#07#客製化-使用FacebookAuthService
這個plugin預設是會在第一次登入時,建立一個SysUser(Spring Security User),然後把username設定為"facebook_xxxxxxx" xxxxxx代表facebook user id,同時assign ROLE_USER與ROLE_FACEBOOK,最後再建立一個Member(FacebookUser),預設寫入uid(=facebook user id)、accessToken與accessTokenExpires

我這裡的作法會示範透過API取得該User在Facebook上的email,並且以email當做SysUser.username,並設定Member.email

步驟如下:
在src/groovy新增一個FacebookAuthService.groovy
我這裡改寫afterCreate的method,也就是當使用者第一次登入,並且已經新增完SysUser與Member後,才會執行的method。

class FacebookAuthService {

    static transactional = true
def grailsApplication
    void afterCreate(itri.Member user, FacebookAuthToken token){
def appid = grailsApplication.config.grails.plugins.springsecurity.facebook.appId;
def secret = grailsApplication.config.grails.plugins.springsecurity.facebook.secret;


def url = “https://graph.facebook.com/me?access_token="+user.accessToken; 

def result = [:]
try {
def conn = url.openConnection()
conn.doOutput = true
conn.doInput = true

def paramString = “access_token="+user.accessToken; 

conn.outputStream << paramString
result = JSON.parse(conn.inputStream.text)
} catch (Exception ex) {
ex.printStackTrace()
}

if(result.email){
user.email = result.email

user.user.username = result.email
user.user.save(flush: true)
}

}
}

大功告成!!!

其他還有很多可以改寫的Method,可以參考官方說明文件

Gist的程式碼內嵌到Google的Blogger

以往要Blogger分享程式碼,一種是自己寫一些taglib或是css,不然就是到某些線上服務的網站進行一次性轉碼。

第一種方式往往比較不能根據不同語言呈現語法的效果,第二種則是程式碼維護不方便。GitHub上提供了一個不錯的線上服務Gist,一個針對程式碼所設計的平台,不但能夠在貼上程式碼後立即產生分享鏈結,還能依照不同的程式語言來加入高亮(Highlight)效果,讓使用者更易閱讀。

Gist也有提供程式碼內嵌的服務,讓你可以把程式碼嵌在你的網頁中,它提供的內嵌語法如下:

<script src="https://gist.github.com/become/4978229.js"></script>

但是這段程式碼貼到Blogger卻無法顯示,查了一下,可以這樣做

在編輯文章時透過HTML編輯器,在文章內加上以下語法

<script src="https://raw.github.com/moski/gist-Blogger/master/public/gistLoader.js" type="text/javascript"></script>

然後再你要放程式碼的地方加上

<div class="gistLoad" data-id="GistID" id="gist-GistID">Loading ....</div>

然後把GistID換成你程式碼的ID即可

[Grails]前端可同時輸入多個子物件的方法(One-Many)

使用Grails開發系統時,經常會設計有許多一對多的對映關係,例如:一個人有多個電話、住址、電子郵件或是銀行帳戶,或者是一個物件可以上傳多個檔案、照片等。此時雖然可以輕易在domain class做好一對多的對映設定,但是在前端使用者介面,要新增多個子物件就需要一點技巧了。

這裡以一個禮物(Gift)對定多個連結(SysLink)為例子,大致說明一下需要修改的部份:

Gift Model主要就是設定對映多個連結(SysLink),以及cascade設定
Gift.groovy

Loading ….

SysLink最主要是要設定deleted的transient屬性,在前端可以用來是記錄使用者預計刪除的檔案。
SysLink.groovy

Loading ….

設定好Model後,就開始在view上面做手腳了,我們在想要新增/修改的頁面上透過render template的方式來做。

我這裡的範例是寫在透過generate-view自動產生的_form.gsp裡面,因為會用到jquery的一些語法,記得順便include進來

<g:javascript library="jquery" plugin="jquery"/>

在要產生links輸入區塊加入以下程式碼,就是去透過_links.gsp來render此區塊,並且把giftInstance參數傳過去。

<g:render template="links" model="[‘giftInstance’:giftInstance]" />

_links.gsp處理新增連結的Javascript,如果是其他欄位需求,自己去修改即可,原本已經在資料庫的資料則是透過render _link.gsp來達成

Loading ….

_link.gsp是用來呈現原本的資料,當使用者在前端刪除該筆資料時,透過Javascript是把deleted的屬性設定為true,並將該筆資料隱藏,如此一來當資料儲存時,就可以在Controller裡面去判斷哪些資料要新增,哪些資料要刪除。

Loading ….

GiftController.groovy在update屬性裡面要加上判斷,處理要刪除的資料

Loading ….

參考資料:
http://omarello.com/2010/08/grails-one-to-many-dynamic-forms/

Grails+台灣電話號碼的contraint

在Grails的Domain Object設定中,可以透過constraints的設定來讓檢查使用者輸入的文字,本篇是想針對台灣的電話號碼寫一個contraint。

在domain object上面想要應用正規表示式(Regular Expression)的寫法如下

static constraints = {
contactPhone(matches: “電話的正規表示式")
}

台灣的電話號碼大多分為下面幾種

市話

  • 格式為區碼+電話號碼
  • 區碼為2-3碼
  • 開頭是0
  • 電話號碼則為6到8碼
  • 可能有分機(1~5碼)

如此一來正規表示式可以寫成 0\d{1,2}(\d{6,8})
如果接受使用可以輸入"-“來分隔區碼的話,可以寫成0\d{1,2}-?(\d{6,8}),其中問號代表"-“可有可無。

如果需要分機,假設最多分機為5碼,且可有可無,可以寫成 0\d{1,2}-?(\d{6,8})(#\d{1,5}){0,1}

手機

  • 10碼
  • 09開頭
其正規表示式可以寫成09\d{2}-?(\d{3})-?(\d{3})

如果還做成mask的方式讓使用者清楚如何輸入,例如(_ _ _)_ _ _ _ – _ _ _ _(#_ _ _ _ _)
可以參考jquesy的plugin http://www.slideshare.net/Marcelocajueiro/mask-validator-gem-with-tricks