APIããŒã¿ã®æ©èœã¯éåžžã«åå§çã§ããããã¯ãããžãŒã¯ã·ã³ãã«ã§ãããå®è£ ã¯ãŸã£ããåãã§ã·ã³ãã«ã§ãã ãããããã®æè¡ã«æ £ãããšãç¹å®ã®ãœãŒã·ã£ã«ãããã¯ãŒã¯ã®ããã¥ã¡ã³ããšAPIã®äŸã§ã¯äžååã§ãã ããã«ããããã¯ã§è¿°ã¹ãããŠããããã«ã䜿çšãããèšèªã¯Javaã§ãããæçšãªæ å ±ã®éãèªåçã«åæžãããŸãã ãŸããRuNetã®èª¬æã«ã¯ããã»ã©å€ããããŸããã æãæµæã®å°ãªãæ¹æ³ã§ãµãŒãããŒãã£ã®RESTful補åã䜿çšã§ããŸãããaïŒããã»ã¹ãå®å šã«ç解ããããšã¯ã§ããŸããã bïŒå¿ èŠãªããã»ã¹ã®åãæ¿ãç¹æ§ãæžãããŸãã cïŒå€ãã®å ŽåããµãŒãããŒãã£è£œåã®èª¿æ»ã¯ããã®å®è£ ãéçºãããããé£ããå ŽåããããŸãã ãã®ãããªãµãŒãããŒãã£è£œåã®äœ¿ããããã¯ãéçºãå€§å¹ ã«ä¿é²ã§ããŸããã ãã ãããã®ã¬ãã¥ãŒã§ã¯ãæ®éæ§ãæãªãããšãå«ããŠããã¹ãŠã®ããã»ã¹ãæ倧éã«å¶åŸ¡ããããšã«å人çã«éç¹ã眮ããŠããŸãïŒç¹å®ã®ãµã€ãã«ç¹å®ã®æ©èœããåºå®ãããããããããããå Žé¢ã§ãæ®éçãªè£œåã«ããŸãïŒã ããã«ããŠãŒã¶ãŒèªèšŒã®å®è£ ã ãã§ãªããSpring Security 3ãã¬ãŒã ã¯ãŒã¯ãæäŸãããããžã§ã¯ãã»ãã¥ãªãã£ã·ã¹ãã ã®å®è£ ã«ãèå³ããããŸãã
ãã©ãããã©ãŒã ãšããŒã«ã®äœ¿çšã»ããïŒ Spring Core 3.1 ã Spring MVC 3.1 ã Spring Security 3.1 ã Hibernate 4.1 å®è£ ãããžã§ã¯ãã¯å€åœã®ãã®ã§ãããããå®è£ ããããœãŒã·ã£ã«ãããã¯ãŒã¯ã®ã»ããã¯ã Facebook ã Twitter ã Google + ã LinkedInãªã©ã®ã圌ãã«ãšã£ãŠãæšæºã§ãã
Springããã±ãŒãžã«ã¯ããããã«äœ¿ãããæ¢æãããžã§ã¯ãããããŸããSpringSocialïŒä»æ¥ã®ãªãªãŒã¹1.0.2ïŒã¯ã補åã®Springãã¬ãŒã ã¯ãŒã¯ã«èããã«ãã»ã«åãããä»ã®Spring補åã§äœ¿çšããããã«èšèšãããŠããŸãã 確ãã«ããã¯ãããã§ãã·ã§ãã«ãªãœãªã¥ãŒã·ã§ã³ã«ãªããŸãããç§ãã¡ã®ã¿ã¹ã¯ã¯ããã¹ãŠãå¶åŸ¡ããç解ã§ããããã«ããã»ã¹ãå¯èœãªéãéæã«ããããšã§ãã ãŸãããœãŒã·ã£ã«èªäœã§ã¯ããã¹ãŠãããã»ã©ã¹ã ãŒãºã§ã¯ãããŸããã
1.ã¢ãã«ã
POJO ã UserDetails ãããã³EntityããŠãŒã¶ãŒãªããžã§ã¯ãã«çµã¿åãããŠãå€å°å±éºã§ççŸãããã¹ãåããŸããã ããã°ã©ãã³ã°ææ³ã®èŠ³ç¹ããã¯ããã¯ééã£ãŠããŸãããaïŒéåžžã«äŸ¿å©ã§ãã bïŒè€æ°ã®ã¬ã€ã€ãŒã®äœæãä¿åããPOJO + EntityãUserDetailsãDTOãåå¥ã«å®è¡ããŠãã³ã³ãã³ããå®éã«è€è£œããŸãã
ææ¡ãããŠããã¢ãã«æ§ç¯ã¹ããŒã ã¯æ¬¡ã®ãšããã§ãã

ãããžã§ã¯ãã®æ¿èªããžãã¯ãšããžãã¹ããžãã¯ã«å¹²æžããªãããã«2ã€ã®ã¬ã€ã€ãŒïŒAuthUserãšDataUserïŒãéžæããŸããïŒèšªåè ã管çè ãããã³ä»ã®åãæ¹æ³ã§ãã°ã€ã³ããŸãããç¬èªã®ããããã£ã»ããããããŸãã ããšãã°ãç§ã®ãããžã§ã¯ãã«ã¯æ±è·è ãšéçšäž»ãããŸãã圌ãã¯åãæ¹æ³ã§ãµã€ãã«ã¢ã¯ã»ã¹ããŸãããã¢ãã«æ§é ã¯ãŸã£ããç°ãªããŸãã
ã¬ã€ã€ãŒå ã®æ§é ã®åé¢ã«é¢ããŠã¯ãæããã§ã-FacebookãTwitterãªã©ããåä¿¡ãããã£ãŒã«ãã®ã»ããã¯ãç¹ã«æšæºã®æ¿èªã§ã¯ãéåžžã«ç°ãªã£ãŠããããããã¹ãŠã«å¯ŸããŠ1ã€ã®ã²ã©ãåŒã䌞ã°ãããæ§é ãäœæããããšã¯ãããŒã¿ããŒã¹æ§ç¯ã®èŠ³ç¹ããã¯ã°ãããŠããŸã-é床ã«ã ã¹ã±ãŒã©ããªãã£ã«é¢ããŠã¯ãæ°ãããµãŒãã¹ãããã€ããŒãè¿œå ããå Žåããã®ãããªæ§é ã§äœæ¥ããããšã¯éåžžã«äžäŸ¿ã§ãã
ãªã¹ãããããªããžã§ã¯ãã®ããã€ãã®ãªã¹ããããã³äœ¿çšãããŠããåæã¯ã©ã¹ã
AuthUser.javaïŒ
@ Entity @ Table(name = "auth_user") @ Inheritance(strategy = InheritanceType.JOINED) public class AuthUser implements Serializable, UserDetails { @ Id @ Column(name = "id") @ GeneratedValue(strategy = GenerationType.AUTO) private Long id; @ Column(name = "identification_name", length = 64, nullable = false) private String identificationName; @ Enumerated(EnumType.STRING) @ Column(name = "type", nullable = false) private AuthorityType type; @ Column(name = "binary_authorities", nullable = false) private Long binaryAuthorities; @ Column(name = "enabled", nullable = false, columnDefinition = "tinyint") private Boolean enabled; @ Transient private Set<Authority> authorities; @ OneToOne(fetch = FetchType.LAZY, orphanRemoval = true) @ Cascade({CascadeType.ALL}) @ JoinColumn(name="user_id") private User user; @ Override public Collection<? extends GrantedAuthority> getAuthorities() { authorities = EnumSet.noneOf(Authority.class); for (Authority authority : Authority.values()) if ((binaryAuthorities & (1 << authority.ordinal())) != 0) authorities.add(authority); return authorities; } public void setAuthority(Set<Authority> authorities) { binaryAuthorities = 0L; for (Authority authority : authorities) binaryAuthorities |= 1 << authority.ordinal(); } @ Override public String getPassword() { return type.name(); } @ Override public String getUsername() { return identificationName; } @ Override public boolean isAccountNonExpired() { return true; } @ Override public boolean isAccountNonLocked() { return true; } @ Override public boolean isCredentialsNonExpired() { return true; } //getters/setters }
AuthorityType.javaïŒ
public enum AuthorityType implements Serializable { SIMPLE, FACEBOOK, TWITTER, GOOGLE, LINKEDIN; }
Authority.javaïŒ
public enum Authority implements GrantedAuthority { NEW_CUSTOMER, CUSTOMER, ADMINISTRATOR; @ Override public String getAuthority() { return toString(); } }
FacebookAuthUser.javaïŒ
@ Entity @ Table(name = "facebook_auth_user") public class FacebookAuthUser extends AuthUser { @ Column(name = "first_name", length = 32) private String firstName; @ Column(name = "last_name", length = 32) private String lastName; @ Column(name = "email", length = 64) private String email; @ Column(name = "token", length = 128) private String token; //any number of available properties //getters/setters }
TwitterAuthUser.javaïŒ
@ Entity @ Table(name = "twitter_auth_user") public class TwitterAuthUser extends AuthUser { @ Column(name = "screen_name", length = 64) private String screenName; @ Column(name = "oauth_token", length = 80) private String oauthToken; @ Column(name = "oauth_token_secret", length = 80) private String oauthTokenSecret; //any number of available properties //getters/setters }
SimpleAuthUser.javaïŒ
@ Entity @ Table(name = "simple_auth_user") public class SimpleAuthUser extends AuthUser { @ Column(name = "password", length = 40, nullable = false) private String password; @ Column(name = "uuid", length = 36, nullable = false) private String uuid; @ Override public String getPassword() { return password; } //getters/setters }
ã芧ã®ãšãããå°ããªãååŠãããªãããã§ã¯ãããŸããã
- ãŠãŒã¶ãŒããŒã«ãä¿åããããã®å¥ã®æ§é ïŒããŒãã«ïŒãäœæãããã¯ãããŸããããŸããããŒã«ã»ããã1ã€ã«å€æŽããããšã«ããããŠãŒã¶ãŒã«è€æ°ã®ããŒã«ãä»äžããæ©èœã奪ããããªãã§ãã ãããã£ãŠãããŒã¿ããŒã¹ã«ããŒã«ã»ããã®ãã€ããªè¡šçŸãæ ŒçŽããSpring Securityãã»ããããã£ãŒãããŸãã ããŒã¹ããèªã¿åããšãã«èŠããŠããã¹ãäž»ãªããšã¯ãå€æãè¡ãããšã§ãã ã€ããªãã®ãŒçã«ã翻蚳ã¡ã«ããºã ã¯POJOã«ä¿æããã®ãééã£ãŠãããããã³ã³ãããŒã©ãŒãŸãã¯DAOã«æ®ãå¿ èŠããããŸãããããã¯å ¬éã³ã¹ããšèŠãªãããŸãã
- ãã£ãŒã«ãã¿ã€ãïŒenum AuthorityTypeïŒ-ããŒã¿ããŒã¹å ã®ããŒã¿ãèŠèŠåããããã®ç¹å¥ãªå¿ èŠæ§ã¯ãããŸãããããã«ããã¥ãŒã®äžã§user.getTypeïŒïŒã䜿çšããæ¹ãã¯ã©ã¹ã®1ã€ïŒ TwitterAuthUserã®ãŠãŒã¶ãŒã€ã³ã¹ã¿ã³ã¹ïŒã調ã¹ããããç°¡åã§ãã
- UserDetailsã€ã³ã¿ãŒãã§ãŒã¹ã«ã¯ãããã€ãã®ã¡ãœãããå®è£
ããå¿
èŠããããŸãã ç¹ã«ãidentificationNameïŒããã³getUsernameïŒïŒ ïŒã¯èå¥åãæ ŒçŽããããã£ãŒã«ãã§ããFacebookã®å Žåã¯FacebookID ãTwitterã®å Žåã¯TwitterID ãæšæºèªèšŒã®å Žåã¯ããã¯ããŒã ãŸãã¯ã¡ãŒã«ã§ãã ç§ã®å Žåã®getPasswordïŒïŒã¡ãœããã¯åãã¿ã€ããè¿ããSpring Securityãããã䜿çšããŠRememberMeã¡ã«ããºã ã§Cookieã®ããã·ã¥ãäœæããŸãã åã¯ã©ã¹ã®ãããžã§ã¯ãã®ã»ãã¥ãªãã£ã匷åããã«ã¯ã SimpleAuthUserã¯ã©ã¹ã§è¡ã£ãããã«ãå®éã«ã»ãã¥ãªãã£ããŒã¿ãå²ãåœãŠãããšã«ããããã®ã¡ãœããããªãŒããŒã©ã€ãã§ããŸãã ãã®ä»ã®å ŽåãããŒã¯ã³ãŸãã¯ã·ãŒã¯ã¬ããããŒã¯ã³ã«ããããšãã§ããŸãã ã¡ãœãããšæœåšçã«å¯Ÿå¿ããããããã£ã§æ¬¡ã«è¡ãããšisAccountNonExpired ã isAccountNonLocked ã isCredentialsNonExpired-å¿
èŠã«å¿ããŠãã®ãããªããŒã¿ã䜿çšããããšã決å®ãããã®ã¬ãã¥ãŒã§ã¯äœ¿çšããã return trueã ownæ»ãããŸã ã
å³ãšã³ãŒããããããããã«ã1察1ã«é¢é£ããŠããã«ãããããããç°ãªãã¬ã€ã€ãŒã®ãªããžã§ã¯ãéã§é 延é¢ä¿ã䜿çšããããšã«ããŸããã 2ã€ã®ç®æšããããŸãïŒ1ïŒAuthUserã¯å€ãã®å Žåãã³ã³ãããŒã©ãŒãšãã¥ãŒã®ãã¬ãŒã ã¯ãŒã¯ããžã£ãŒã¯ããäŸåæ§é ããã®èåŸã®ã©ãã«ã§ããã©ãã°ããããšãã欲æ±ã¯ãããŸããã 6ãLAZYãã«ãŠã³ãããŸãã-ãããã¯é»è©±ãäœæãè·æ¥ããã®ä»ã®äž¡æ¹ã§ãïŒããããã£ãŠãç§ã®æèŠã§ã¯ãåä¿éºã¯å·ã€ããŸããã 2ïŒãããã®ã¬ã€ã€ãŒãç°ãªãããžãã¯ã¬ã€ã€ãŒã«å±ããŠããããšãå¿ããŠã¯ãªããŸããïŒAuthUserã¯Spring Securityãã¬ãŒã ã¯ãŒã¯ãšé£æºããŠãããåæã«DataUserã®å€æŽãçºçããå¯èœæ§ããããŸãããåžžã«ç£èŠããã³æŽæ°ããããããŸããã ãã®æ±ºå®ã¯è°è«ã®äœå°ããããæçµçãªãµããããŠããªãããšã«åæããŸãã ããããä»ã®æ¹æ³ã§æ¥ç¶ããå¿ èŠããããããã«ãã£ãŠåé¡ããªã¹ãããããŸãŸã«ãªãããã€ã§ãããžãã¹ããžãã¯ããèªèšŒBeanããã«ã§ããŸãã ããã¯ãéçºè ã®è£éã«ãããŸãã
DataUserã¯ã©ã¹ãšäŸåã¯ã©ã¹ã«ã€ããŠã¯ããããã¯åçŽãªPOJOã¯ã©ã¹ã§ããDataUserã«ã¯ãã¹ãŠã«å ±éã®ããããã£ïŒidãfirstNameãlastNameãemailãlocationãªã©ïŒãçŽæ¥å«ãŸããæ®ãã¯ããèªäœã«åºæã®ããããã£ãè¿œå ããããšã§æ¡åŒµãããŸãïŒãªã¹ãã¯éå®çšçã§ãïŒ ã
2.ã³ã³ãããŒã©ãŒã
ååãšããŠã èªèšŒãšæ¿èªã®çšèªã§ã¯ããã»ã©éãã¯ãããŸãããæ¿èªã¯æ¿èªã§ãããããã«ãç°ãªããããã¯ãŒã¯ãããã€ããŒã¯ãããã®çšèªãç¬èªã®æ¹æ³ã§åŸæãããŸãã ããããç§ã®ã¬ããŒãã§ã¯ãç»é²ãšçŽæ¥èªèšŒãŸãã¯ãã°ã€ã³ïŒäž¡æ¹ãšããœãŒã·ã£ã«ãããã¯ãŒã¯ãããã€ããŒããã®èªèšŒã«åºã¥ããŠããŸãïŒãšãã2ã€ã®æŠå¿µãæ確ã«åºå¥ããŠããŸãã ãã©ãŒã©ã ã«åå ãããšãããŸãã¯ã³ã¡ã³ããéä¿¡ãããšãã¯ããã°ã€ã³ããã ãã§ãïŒæåã®ãšã³ããªã§ããããš100åã®1ã§ããããšïŒã ç»é²ç³è«æã«ãŠãŒã¶ãŒã¢ãã«ãäœæããå¿ èŠããããããç»é²ãšåçŽãªæ¿èªã®åé¢ãè¿œæ±ããŠããŸãã ãããŠãããã¯ç°¡åã«å®è£ ã§ããŸãããå ¥ãå£ã§ãã®ãããªäººããããã©ããã確èªããæåã®ãã°ã€ã³ã®å Žåã«ãŠãŒã¶ãŒæ§é ãäœæããŸãã ããããaïŒæšæºçãªç»é²ãããããããã«1ã€ãããã«ãã1ã€ãïŒæªåé«ããŠãŒã¶ããªã㣠ïŒãèŠèŠçã«åé¢ããããšã¯è«ççã§ãã bïŒã©ããªã«no蟱çã§ãã£ãŠãããœãŒã·ã£ã«ãããã¯ãŒãã³ã°APIã¯é¡§å®¢ã«é¢ããæ å ±ãæäŸããããšã«å šäŒäžèŽã§ã¯ãããŸãããããšãã°ã Facebook APIã¯é»åã¡ãŒã«ãåãå§ãæ§å¥ãå ŽæãæäŸããŸãã Twitter API -screen_nameãæäŸããŸããããã¯ããåãå§ãã§ã¯ãªãå ŽåããããŸãããé»åã¡ãŒã«ã¯æäŸããŸããïŒå®éãšä»®æ³ãæ確ã«åºå¥ããç«å ŽããããŸãïŒã Google+ APIã¯åãå§ãã¡ãŒã«ãæäŸããŸãããå Žæã«ã€ããŠã¯äœãæäŸããŸããã LinkedIn API-ååãå§ãæ§å¥ãå Žæããã ããã¡ãŒã«ã¯éä¿¡ããŸããã ç§ã®ãããžã§ã¯ãã¯èšªåè ã®å人ããŒã¿ïŒæ¡çšäŒæ¥ã®ãããžã§ã¯ãïŒãšéåžžã«å¯æ¥ã«çµã³ã€ããŠãããããç»é²ãšãšãã«ãããã€ãã®ãã£ãŒã«ãã«èšå ¥ããå¿ èŠãããããšã瀺ããŸãïŒæåã¯ãFacebookãŠãŒã¶ãŒãé€ããŠã誰ããå°ãªããšãäœããæå®ããå¿ èŠããããŸããã TwitterãŠãŒã¶ãŒã¯ãå®å šãªæåŠãé€å€ããããã§ã¯ãããŸããããå¿ èŠã«å¿ããŠãã£ãŒã«ãã«å ¥åããŸããããšãã°ããã®ãããªæ å ±ããã§ã«å¿ èŠãªããŸãŒã³ãã«ç§»åããããšããå Žåãªã©ïŒ ãããã£ãŠãæ¿èªã¡ã«ããºã ãããã«ç解ããã®ã«åœ¹ç«ã€ã ãã§ãããç§ã®å®è£ ã¯ããèšãã¿ãŸãã
ä»äºïŒãŸãã¯ãã¹ãïŒã§ã¯ãåãœãŒã·ã£ã«ãããã¯ãŒã¯ã§ç¬èªã®ã¢ããªã±ãŒã·ã§ã³ãäœæãããã®èšå®ã䜿çšããŠäœæ¥ããå¿ èŠãããããšãæãåºããŠãã ããã Facebookã®å Žåãããã¯developer.facebook.com/appsãTwitterã®å Žå-dev.twitter.com/appsãGoogle+ã®å Žå-code.google.com/apis/consoleãLinkedInã®å Žå-www.linkedin.com/secure/developerã§ãã ã¢ããªã±ãŒã·ã§ã³ãäœæãããšããåãããã€ããŒãæã€3ã€ã®ãã©ã¡ãŒã¿ãŒãéèŠã§ãïŒããŒïŒãŸãã¯APIããŒãã³ã³ã·ã¥ãŒããŒããŒãã¯ã©ã€ã¢ã³ãIDïŒãã·ãŒã¯ã¬ããããŒïŒã¢ããªã·ãŒã¯ã¬ãããã³ã³ã·ã¥ãŒããŒã·ãŒã¯ã¬ãããã¯ã©ã€ã¢ã³ãã·ãŒã¯ã¬ãããã·ãŒã¯ã¬ããããŒïŒããã³ãªãã€ã¬ã¯ãã¢ãã¬ã¹ïŒæè¿ãŸã§ïŒäžéšã®ãããã€ããŒã§ã¯localhostãžã®ãªãã€ã¬ã¯ããæ©èœããŠããŸããã§ããããä»æ¥ã¯httpïŒ// localhostïŒ8080 / myprojectã®ãããªã¢ãã¬ã¹ã§å šå¡ãæ©èœããããšã確èªããŠããŸã ã ãŸããã¢ããªã±ãŒã·ã§ã³ã®ããŽãªã©ãä»ã®ãã©ã¡ãŒã¿ãŒãæ§æããããšãã§ããŸãããLinkedInã§ã¯ãã€ã¡ãŒãžãžã®ãªã³ã¯ãSSLã§ããããšãå¿ èŠã§ãïŒç解ã§ããªãé¡ãïŒã
FacebookãšGoogle+ã¯é·ãéæ°ããOAuth 2ãããã³ã«ã䜿çšããŠãããTwitterãšLinkedInã¯åŒãç¶ãå€ãOAuthãããã³ã«ã䜿çšããŠããŸãïŒGoogle+ã¯2012幎4æ20æ¥ãŸã§OAuthã®æåã®ããŒãžã§ã³ããµããŒãããŠããŸããïŒã ç§ã®è£éã§ïŒå¥ã®æèŠããã£ããšã¯æ³åã§ããŸãããïŒãOAuth 2ã䜿çšããäœæ¥ã¯æ¯é¡ãªãã·ã³ãã«ã§äŸ¿å©ã§ãããéåžžã«äººæ°ãããã«ãããããããæšæºãšããŠæ¿èªãããŠããŸããã æäœã®åçã¯éåžžã«åå§çã§ãïŒæãäžè¬çãªã¹ããŒã ïŒïŒ

ãã®ããããŠãŒã¶ãŒã¯WebããŒãžã®ç»é²ãã¿ã³ã®ãããããã¯ãªãã¯ããŸãã

ïŒãããŠãããŒãžã«ãè¿œå ãæ©èœãæ®ããã www.myproject.com / registration / facebookãªã©ã®ã¢ãã¬ã¹ãæã€ãã¿ã³ã®ã¿ãæ®ããŸãïŒããªã¯ãšã¹ãã¯ã³ã³ãããŒã©ãŒã«éãããŸãïŒFacebookã®å ŽåïŒïŒ
@ RequestMapping(value = "/registrate/facebook", method = RequestMethod.POST) public ModelAndView facebookRegistration() throws Exception { return new ModelAndView(new RedirectView(FACEBOOK_URL + "?client_id=" + FACEBOOK_API_KEY + + "&redirect_uri=" + FACEBOOK_URL_CALLBACK_REGISTRATION + + "&scope=email,user_location&state=registration", true, true, true)); }
ã¹ã³ãŒãã®ãã©ã¡ãŒã¿ãŒã¯developer.facebook.com/docs/authentication/permissionsã§èŠã€ããããšãã§ããŸãïŒTwitterã®å Žå-dev.twitter.com/docs/platform-objects/usersãGoogle +ã®å Žåã¯developer.google.com/accounts/docs/OAuth2Login# userinfocall ãLinkedIn-developer.linkedin.com/ documents /profile- fields ïŒãããã«ã«ããã«ãé£ããŠããŸããã redirect_uriãã¡ã€ã³ã¯ãã¢ããªã±ãŒã·ã§ã³ã®ç»é²ã¢ãã¬ã¹ãšäžèŽããå¿ èŠããããŸãã stateã¯ãç¡æãã®ãã©ã¡ãŒã¿ãŒã§ãããç»é²ããµã€ã³ã€ã³ãèªåãµã€ã³ã€ã³ãªã©ã®è¿œå ã¢ã¯ã·ã§ã³ã®ã»ããã©ãšããŠäœ¿çšããŸãã
次ã«ããŠãŒã¶ãŒã¯Facebookãã°ã€ã³ããŒãžã®æ¿èªã«ããªãã€ã¬ã¯ããããŸããããã§ãã¢ããªã±ãŒã·ã§ã³ãããŒã¿ã䜿çšã§ããããã«ããèš±å¯ãåºæ¬çãªèš±å¯ãè¶ ããŠããå Žåãèš±å¯ãŠã£ã³ããŠã«ãªã¹ããããŸãã
æ¿èªåŸããããã³ã°FACEBOOK_IRL_CALLBACK_REGISTRATIONãåããã³ã³ãããŒã©ãŒãåŒã³åºããåä¿¡ããŸãïŒã¯ã©ã€ã¢ã³ãã«ããä»»æã®æ±ºå®-ãã°ã€ã³ããã£ã³ã»ã«ãæ»ãïŒã Spring MVCã§ã¯ããããã³ã°ã«ãã£ãŠãªã¯ãšã¹ãããã£ã«ã¿ãªã³ã°ã§ããŸãïŒãã®å Žåããããžã§ã¯ãã®ãããã³ã°ãæäŸãããŸãïŒã
@ RequestMapping(value = "/callback/facebook", method = RequestMethod.GET) public class FacebookController extends ExternalController implements Constants { @ RequestMapping(value = "/registration", params = "code") public ModelAndView registrationAccessCode(@ RequestParam("code") String code, HttpServletRequest request) throws Exception { String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_REGISTRATION, FACEBOOK_API_SECRET, code}); String token = Utils.parseURLQuery(authRequest).get("access_token"); String tokenRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token}) Map<String, Json> userInfoResponse = Json.read(tokenRequest).asJsonMap(); String email = userInfoResponse.get("email").asString().toLowerCase(); String id = userInfoResponse.get("id").asString(); //verifying ... is new? is email in DB? //creating objects Customer customer = new Customer(); customer.setEmail(email); //... customerer = (Customerer) userDAO.put(customer); FacebookAuthUser user = new FacebookAuthUser(); user.setFirstName(firstName); //... user.setIdentificationName(id); user.setToken(token); user.setType(AuthenticationType.FACEBOOK); user.setEnabled(true); user.setAuthority(EnumSet.of(Authority.CUSTOMER)); user.setUser(customer); authenticationDAO.put(user); return new ModelAndView(new RedirectView("/registrate.complete", true, true, false)); } @ RequestMapping(value = "/registration", params = "error_reason") public ModelAndView registrationError(@ RequestParam("error_description") String errorDescription, HttpServletRequest request, HttpServletResponse response) { //return client to registration page with errorDescription return new ModelAndView(new RedirectView("/registrate", true, true, false)); } //will signin and signinError }
å©äŸ¿æ§ãšåäžã®äœ¿çšã®ããã«ããã®ãªã¹ãã§äœ¿çšãããUtilsã¯ã©ã¹ã®ããã€ãã®éçã¡ãœããïŒ
public static String sendHttpRequest(String methodName, String url, String[] names, String[] values) throws HttpException, IOException { if (names.length != values.length) return null; if (!methodName.equalsIgnoreCase("GET") && !methodName.equalsIgnoreCase("POST")) return null; HttpMethod method; if (methodName.equalsIgnoreCase("GET")) { String[] parameters = new String[names.length]; for (int i = 0; i < names.length; i++) parameters[i] = names[i] + "=" + values[i]; method = new GetMethod(url + "?" + StringUtils.join(parameters, "&")); } else { method = new PostMethod(url); for (int i = 0; i < names.length; i++) ((PostMethod) method).addParameter(names[i], values[i]); method.setRequestHeader("Content-Type", "application/x-www-form-urlencoded"); } new HttpClient().executeMethod(method); return getStringFromStream(method.getResponseBodyAsStream()); } public static Map<String, String> parseURLQuery(String query) { Map<String, String> result = new HashMap<String,String>(); String params[] = query.split("&"); for (String param : params) { String temp[] = param.split("="); try { result.put(temp[0], URLDecoder.decode(temp[1], "UTF-8")); } catch (UnsupportedEncodingException exception) { exception.printStackTrace(); } } return result; }
å®æ°ïŒ
final public static String FACEBOOK_API_KEY = "XXXXXXXXXXXXXXXX"; final public static String FACEBOOK_API_SECRET = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"; final public static String FACEBOOK_URL = "https://www.facebook.com/dialog/oauth"; final public static String FACEBOOK_URL_ACCESS_TOKEN = "https://graph.facebook.com/oauth/access_token"; final public static String FACEBOOK_URL_ME = "https://graph.facebook.com/me"; final public static String FACEBOOK_URL_CALLBACK_REGISTRATION = SITE_ADDRESS + "/callback/facebook/registration"; final public static String FACEBOOK_URL_CALLBACK_SIGNIN = SITE_ADDRESS + "/callback/facebook/signin";
誰ã§ãèªç±ã«JSONã©ã€ãã©ãªã䜿çšã§ããŸããç§ã¯mjsonã©ã€ãã©ãªïŒ http://sharegov.blogspot.com/2011/06/json-library.html ïŒã䜿çšããŸãã-å°ããã䟿å©ã§ãã·ãªã¢ã«åãäžèŠã§ãã
ã芧ã®ãšãããããã»ã¹ã¯åçŽã§ãããç¹å¥ãªè³ªåãããã¹ãã§ã¯ãããŸããã ãŸããFacebookãäœçœ®ãã©ã¡ãŒã¿ãŒãæäŸãããã®å€ããGoogle Maps APIã ãã¹ãªãããããŠïŒ http://maps.googleapis.com/maps/api/geocode/json㧠ïŒã䟿å©ãªåœ¢åŒã§å°çäœçœ®æ å ±ãåŒãåºãããšã«æ³šæããŠãã ãã ïŒæšæºã§ïŒ GoogleãããïŒã ããã¯ãèªåã®Facebookã¢ã«ãŠã³ãã®ã¯ã©ã€ã¢ã³ããå Žæã®åœã ãã§ã¯ãªãããšã瀺ããŠããå Žåã«ã®ã¿å®è¡ã§ããããšã¯æããã§ãã
Google+ãžã®ãµã€ã³ã¢ãããåæ§ã®æ¹æ³ã§è¡ãããŸãããå¯äžã®éãã¯ãã·ã¹ãã ã®ã³ãŒã«ããã¯URLãã¢ããªã±ãŒã·ã§ã³èšå®ã§æå®ããããã®ãšå®å šã«äžèŽããå¿ èŠãããããšã§ãã ãããã£ãŠããã¹ãŠã®ãªãã€ã¬ã¯ãã¯1ã€ã®ãããã³ã°ã®ã¿ã«è©²åœããŸãã ããã»ã¹ãåé¢ããã«ã¯ãè¿ãããç¶æ ãã©ã¡ãŒã¿ãŒã䜿çšãããšäŸ¿å©ã§ãã
@ RequestMapping(value = "/callback/google", method = RequestMethod.GET) public class GoogleController extends ExternalController implements Constants { @ RequestMapping(value = {"/", ""}, params = "code") public ModelAndView googleProxy(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception { ... } @ RequestMapping(value = {"/", ""}, params = "error") public ModelAndView googleErrorProxy(@RequestParam("error") String error, @RequestParam("state") String state, HttpServletRequest request) throws Exception { ... } }
ã¢ãã¬ã¹ãšæ»ããã©ã¡ãŒã¿ãŒãé€ããæ®ãã®ã¢ã¯ã·ã§ã³ã¯åãã§ãã
OAuthèªèšŒïŒTwitterãšLinkedInïŒã§ã¯ç¶æ³ãç°ãªããŸãã ç§ã¯èªèšŒãã§ãŒã³å šäœã調ã¹ãŸããããããã¯ããŒã¯ã³ã§ãªã¯ãšã¹ãã圢æããããéåžžã«äžäŸ¿ã§ã-ç¹å¥ãªæ¹æ³ã§ãæ¥çãããbase64ãããã¯ããæéã®çµéãšãšãã«ãã©ã¡ãŒã¿ãŒãè¿œå ãããªã©ã®æäœãå¿ èŠã§ãã ãããŠæãé©ãã¹ãããš-ãããã®ãœãŒã·ã£ã«ãããã¯ãŒã¯ã®éçºè åãã®ã»ã¯ã·ã§ã³ã«ã¯ããããã®ããã»ã¹ã¯è¡šç€ºãããŸããã ãããã£ãŠãããã¯æšæºã§ãããèšç®ã¯æšæºçãªã¢ãããŒãã«ãªããŸãã ãããã«ããããæåã§ãå®è£ ããããã®æ¹æ³ã§ã®æ¿èªã¯ãã¢ããªã±ãŒã·ã§ã³ã®éçºã«ã¯é¢ä¿ãããŸããã ãããç°¡åã«ãããµãŒãããŒãã£ã®ç¡æã©ã€ãã©ãªã䜿çšããããšããå§ãããŸãã ããšãã°ãTwitterå°çšã®ã©ã€ãã©ãªtwitter4j.jarããããŸãã MITã©ã€ã»ã³ã¹ã®æš©å©ã®äžã§é åžãããŠããscribe-javaã©ã€ãã©ãªïŒ http://github.com/fernandezpablo85/scribe-java ïŒã䜿çšããŸããã ãã®ããã±ãŒãžã«ã¯ã Digg API ã Facebook API ã Flickr API ã Freelancer API ã Google API ã LinkedIn API ã Skyrock API ã Tumblr API ã Twitter API ã Vkontakte API ã Yahoo API ããã®ä»å€æ°ã®2ã€ã®APIãå«ãŸããŸãã
ã¹ã¯ã©ã€ãã©ã€ãã©ãªã䜿çšããTwitterã®ç»é²ããã»ã¹ã¯æ¬¡ã®ããã«ãªããŸãã ç»é²ããŒãžããã®æ¿èªã®ããã®ã¯ã©ã€ã¢ã³ãèŠæ±ã³ã³ãããŒã©ãŒïŒ
@ RequestMapping(value = "/registrate/twitter", params = "action", method = RequestMethod.POST) public ModelAndView twitterRegistrationJobseeker(HttpServletRequest request) throws Exception { OAuthService service = new ServiceBuilder().provider(TwitterApi.class) .apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET) .callback(TWITTER_URL_CALLBACK_REGISTRATION).build(); Token requestToken = service.getRequestToken(); request.getSession().setAttribute("twitter", service); request.getSession().setAttribute("request_token", requestToken); return new ModelAndView(new RedirectView(service.getAuthorizationUrl(requestToken), true, true, true)); }
Twitterã³ãŒã«ããã¯ã³ã³ãããŒã©ãŒïŒ
@ RequestMapping(value = "/callback/twitter", method = RequestMethod.GET) public class TwitterController extends ExternalController implements Constants { @ RequestMapping(value = "/registration", params = "oauth_verifier") public ModelAndView registrationAccessCode(@ RequestParam("oauth_verifier") String verifier, HttpServletRequest request, HttpServletResponse response) throws Exception { OAuthService service = (OAuthService) request.getSession().getAttribute("twitter"); Token accessToken = service.getAccessToken((Token) request.getSession().getAttribute("request_token"), new Verifier(verifier)); OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS); service.signRequest(accessToken, oauthRequest); Map<String, Json> userInfoResponse = Json.read(oauthRequest.send().getBody()).asJsonMap(); String twitterId = userInfoResponse.get("id").asString(); //verifying ... Customer customer = new Customer(); customer.setFirstName((String) request.getSession().getAttribute("pageValueFirstName")); //... customer = (Customer) userDAO.put(customer); TwitterAuthUser user = new TwitterAuthUser(); user.setAuthority(EnumSet.of(Authority.CUSTOMER)); user.setIdentificationName(twitterId); //... user.setOauthToken(accessToken.getToken()); user.setOauthTokenSecret(accessToken.getSecret()); user.setType(AuthenticationType.TWITTER); user.setUser(customer); authenticationDAO.put(user); return new ModelAndView(new RedirectView("/registrate.complete", true, true, false)); } @ RequestMapping(value = "/registration", params = "denied") public ModelAndView registrationError(HttpServletRequest request) { //response does not contain the error text return new ModelAndView(new RedirectView("/registrate", true, true, false)); } //will signin and signinError }
ç¹°ãè¿ããŸããããã¹ãŠãéåžžã«ã·ã³ãã«ã§æé ãªäŸ¡æ Œã§ãã LinkedIn APIãä»ããç»é²ã¯ããŸã£ããåãæ¹æ³ã§è¡ãããŸãã
æåŸ-æšæºçãªæ¹æ³ã§ã®ç»é²ã æšæº-ãããæšæºã§ããçç±ã§ããã³ãŒãã¯æäŸããŸããããã®çµæãAuthUserããç¶æ¿ããSimpleAuthUseråã®ãªããžã§ã¯ããäœæããããšãæ確ã«ããŸãã
SimpleAuthUser user = new SimpleAuthUser(); user.setAuthority(EnumSet.of(Authority.NEW_CUSTOMER)); user.setEnabled(false); user.setIdentificationName(email); user.setPassword(passwordEncoder.encodePassword(password, email)); user.setType(AuthenticationType.SIMPLE); user.setUser(customer); user.setUuid(uuid); authenticationDAO.put(user);
ãã®å Žåãæš©éNEW_CUSTOMERãå¿ èŠã§ãã -ç»é²æžã¿ãŠãŒã¶ãŒã¯ç»é²ã®ç¢ºèªãå¿ èŠã§ããããïŒæšæºãã©ã¯ãã£ã¹ïŒãaïŒå¥ã®åœ¹å²ããããŸã bïŒSpring Securityãèš±å¯ããããšã¯èš±å¯ãããŠããŸããïŒenabled = falseïŒã
ãµã€ãã§ã®æ¿èª
åçŽãªæ¥ã®application-context-security.xml ïŒ
<security:global-method-security secured-annotations="enabled" jsr250-annotations="enabled" pre-post-annotations="enabled" proxy-target-class="true"/> <security:http auto-config="true" use-expressions="true"> <security:intercept-url pattern="/**" access="permitAll"/> <security:form-login login-page="/signin"/> <security:logout invalidate-session="true" logout-success-url="/" logout-url="/signout"/> <security:remember-me services-ref="rememberMeService" key="someRememberMeKey"/> </security:http> <security:authentication-manager alias="authenticationManager"> <security:authentication-provider ref="authenticationProvider"/> </security:authentication-manager> <bean id="authenticationProvider" class="myproject.security.CustomAuthenticationProvider"/> <bean id="rememberMeService" class="myproject.security.RememberMeService"> <property name="key" value="someRememberMeKey"/> <property name="userDetailsService" ref="userDetailsService"/> </bean> <bean id="userDetailsService" class="myproject.security.CustomUserDetailsManager"/> <bean id="passwordEncoder" class="org.springframework.security.authentication.encoding.ShaPasswordEncoder"/>
CustomUserDetailsManager.javaïŒ
public class CustomUserDetailsManager implements UserDetailsService { @ Resource private AuthenticationDAO authenticationDAO; @ Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { return authenticationDAO.findAuthUser(username); } }
CustomUserAuthentication.javaïŒ
public class CustomUserAuthentication implements Authentication { private String name; private Object details; private UserDetails user; private boolean authenticated; private Collection<? extends GrantedAuthority> authorities; public CustomUserAuthentication(UserDetails user, Object details) { this.name = user.getUsername(); this.details = details; this.user = user; this.authorities = user.getAuthorities(); authenticated = true; } @ Override public String getName() { return name; } @ Override public Collection<? extends GrantedAuthority> getAuthorities() { return authorities; } @ Override public Object getCredentials() { return user.getPassword(); } @ Override public Object getDetails() { return details; } @ Override public Object getPrincipal() { return user; } @ Override public boolean isAuthenticated() { return authenticated; } @ Override public void setAuthenticated(boolean authenticated) throws IllegalArgumentException { this.authenticated = authenticated; } }
CustomAuthenticationProvider.java
ïŒã¯ã©ã¹ã¯å®å šã«æãã§ãããSpring Securityã¯AuthenticationProviderã€ã³ã¿ãŒãã§ãŒã¹ã®åŸç¶ãäŸçµŠããå¿ èŠããããŸãããæå³ã«é¢ããŠæãè¿ãPreAuthenticatedAuthenticationProviderã¯é©åã§ã¯ãããŸããïŒïŒ public class CustomAuthenticationProvider implements AuthenticationProvider { @ Override public Authentication authenticate(Authentication authentication) throws AuthenticationException { // . return authentication; } @ Override public boolean supports(Class<?> authentication) { return PreAuthenticatedAuthenticationToken.class.isAssignableFrom(authentication); } public Authentication trust(UserDetails user) { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication trustedAuthentication = new CustomUserAuthentication(user, authentication.getDetails()); authentication = authenticate(trustedAuthentication); SecurityContextHolder.getContext().setAuthentication(authentication); return authentication; } }
ãããŠãããããã»ãã¥ãªãã£ãæŽçããããã®æããããã«ããã¯ããªå Žæã¯ã RememberMeã¡ã«ããºã ã®å®è£ ã§ãã ååãšããŠã RememberMeãµãŒãã¹ã®æäœãTokenBasedRememberMeServiceså®è£ ãšå®å šã«äžè²«ããããã«ããã¹ãŠããã§ã«æŽçãããŠããŸãã1ã€ã®æ確åïŒèªåã¯ã©ã€ã¢ã³ãèªèšŒã®ãã¹ãŠã®ããŒã¿ã¯ããŒã¿ããŒã¹ã«ãããŸããããŠãŒã¶ãŒããµã€ãã«ãã°ãªã³ããŠããã¢ã«ãŠã³ããåé€ããå ŽåããããŸã .ãããŠãããã¯ççŸããããããŸã-ãŠãŒã¶ãŒãæ¿èªããŸãããå®éã«ã¯åœŒã¯ããã«ããŸãããã€ãŸãããµãŒãããŒãã£ã®ãµãŒãã¹ãä»ããæ¿èªã®äž»ãªååã«éåããŠããŸããã€ãŸããRememberMeã¡ã«ããºã ãããªã¬ãŒããããšãèªåçã«çä¿¡ããã¯ã©ã€ã¢ã³ãã確èªããå¿ èŠããããŸããåãããã¯ãŒã¯ãããã€ããŒã®APIã«ã¯ãã®ãããªã¡ã«ããºã ããããŸãããé©åãªæ®µéã§ç¢ºèªããããã«ãSpringã®RememberMeã®äœæ¥ã«ãããã³ãããããå¿ èŠããããŸããæ®å¿µãªãããã¯ã©ã¹ãæ¡åŒµããŠãæ©èœããŸããïŒAbstractRememberMeServicesã«ã¯finalã«èšå®ããå¿ èŠãããã¡ãœããããããŸãïŒã®ã§ãã¯ã©ã¹ãå®å šã«åå®çŸ©ããå¿ èŠããããŸããç§ã®æ¹æ³ã¯ããé¢åã§ãæåŸããè¡ããŸããããããŠã人éã®å¹³å¡ãªæ doesã¯ãããåçŽãªãªãã·ã§ã³ã«ãããããçŽãããšãèš±ããŸãããAbstractRememberMeServicesã¯ã©ã¹ãå®å šã«åå®çŸ©ããŸããTokenBasedRememberMeServicesã¯ã©ã¹ã®ã³ãŒããå«ããŠããããªãã¯èªèšŒautoLoginã¡ãœããïŒHttpServletRequestãªã¯ãšã¹ããHttpServletResponseã¬ã¹ãã³ã¹ïŒã«æ°è¡ãè¿œå ããŸã-ã¡ãœããã§å€ã確èªããåŸãå³æèªèšŒã®åã«ãã¯ã©ã€ã¢ã³ãã®ãçŸå®ãæ€èšŒã¡ãœãããžã®åŒã³åºããæ¿å ¥ããŸããïŒ
Class<? extends ExternalController> controller = externalControllers.get(user.getPassword()); if (controller != null && !controller.newInstance().checkAccount(user)) return null;
ãããŠä»¥åãã³ã³ã¹ãã©ã¯ã¿ãŒã§éçãªã¹ããå®çŸ©ããŸãã
private Map<String, Class<? extends ExternalController>> externalControllers; public CustomRememberMeService() { externalControllers = new HashMap<String, Class<? extends ExternalController>>(){{ put(AuthenticationType.FACEBOOK.name(), FacebookController.class); put(AuthenticationType.TWITTER.name(), TwitterController.class); put(AuthenticationType.GOOGLE.name(), GoogleController.class); put(AuthenticationType.LINKEDIN.name(), LinkedinController.class); }}; }
ïŒãã®ã³ãŒãã®å®è£ ã¯ãæšæºèªèšŒã®RememberMeã«ã¯äžå圱é¿ããŸããïŒã
ããç°¡åãªæ¹æ³ã¯ãREMEMBER_ME_FILTERãã£ã«ã¿ãŒãç¬èªã®ãã®ã«çœ®ãæããããšã§ãããã®å Žåãäžèšã®autoLoginã¡ãœãããåŒã³åºããåŸãçŽæ¥èªèšŒããåã«åãã³ãŒããé 眮ããå¿ èŠããããŸããã³ãŒãã®æ¹ãå®äŸ¡ã§ç解ããããã§ãããèšå®ã«ä»å ¥ããå¿ èŠããããŸãã誰ããã©ã¡ãã®æ¹æ³ããšããã決ããã§ãããããç§ã®æèŠã§ã¯ã2çªç®ã®æ¹æ³ã¯ã€ããªãã®ãŒçã«ãçŽç²ãã§ãã
ãŸããExternalControllerã¯ã©ã¹ãšcheckAccountïŒuserïŒã®åŒã³åºãã«ã€ããŠãæ確ã«ããå¿ èŠããããŸããç§ã®ãã¹ãŠã®ã³ãŒã«ããã¯ã³ã³ãããŒã©ãŒã¯ExternalControllerã¯ã©ã¹ãæ¡åŒµããŸãã
public abstract class ExternalController { public abstract boolean checkAccount(UserDetails user) throws Exception; }
åã³ã³ãããŒã©ãŒã¯ãã®åäžã®ã¡ãœããããªãŒããŒã©ã€ãããŸããããšãã°ãFacebookã®å ŽåïŒ
public boolean heckAccount(UserDetails user) throws Exception { FacebookAuthUser facebookUser = (FacebookAuthUser) user; String authRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{facebookUser.getToken()}); Map<String, Json> tokenInfoResponse = Json.read(authRequest).asJsonMap(); return tokenInfoResponse.get("error") == null && tokenInfoResponse.get("id").asString().equalsIgnoreCase(facebookUser.getIdentificationName()); }
ããã³Twitterã®å ŽåïŒ
public boolean checkAccount(UserDetails user) throws Exception { TwitterAuthUser twitterUser = (TwitterAuthUser) user; OAuthService service = new ServiceBuilder().provider(TwitterApi.class).apiKey(TWITTER_CONSUMER_KEY).apiSecret(TWITTER_CONSUMER_SECRET).build(); OAuthRequest oauthRequest = new OAuthRequest(Verb.GET, TWITTER_URL_CREDENTIALS); service.signRequest(new Token(twitterUser.getOauthToken(), twitterUser.getOauthTokenSecret()), oauthRequest); String response = oauthRequest.send().getBody(); Map<String, Json> info = Json.read(request).asJsonMap(); return info.get("id").asString().equalsIgnoreCase(twitterUser.getIdentificationName()); }
ãªã©
ãµã€ãèªäœã§ã®çŽæ¥èªèšŒïŒãã°ã€ã³ããµã€ã³ã€ã³ïŒã¯ãç»é²ãšéåžžã«äŒŒãŠããŸãããŠãŒã¶ãŒã¯ããŒãžã«ç§»åããŠããã°ã€ã³ããã¯ãªãã¯ããæ¿èªã«ãªãã€ã¬ã¯ãã

ãŸãããµãŒããŒã«æž¡ãã®ã¯ãããµã€ã³ã€ã³ããŸãã¯ãèªåãµã€ã³ã€ã³ããã©ã¡ãŒã¿ãŒã®ã¿ã§ãããèªåçã«ãµã€ã³ã€ã³ããã§ãã¯ããã¯ã¹ãã¯ãªãã¯ããããã©ããã«ãã£ãŠç°ãªããŸããããã«ããã¹ãŠãç»é²ãšåæ§ã®ã·ããªãªã«åŸã£ãŠçºçãããã©ã¡ãŒã¿ãŒã®å€æŽãã³ãŒã«ããã¯URLã®ã¿ããã¹ãŠã®ã¹ã³ãŒããŸãã¯æš©éã®åé€-ã¯ã©ã€ã¢ã³ãIDãšãã®ããŒã¯ã³ã®ã¿ãååŸããå¿ èŠããããŸããã³ã³ãããŒã©ã®ã¡ãœãããé©åã«ãã§ãã¯ããåŸãããŒã¿ããŒã¹å ã®ããŒã¯ã³ãäžæžãããããšããå§ãããŸãããŸããããšãã°ãFacebookã¯ãã¹ãäžã«ã¯ã©ã€ã¢ã³ãããŒã¯ã³ãå€æŽããŸããã§ããããGoogle +ã¯æ¯åå€æŽããŸãã ãå€æŽããçºçããé »åºŠã¯ããããªãã®ã§ãåaccess_tokenã®åŸã«ïŒå®éã«ã¯ããããã€ããŒã«ããéèªåæ¿èªããšã«ïŒæžãæããŸãã
ãããŠãæãéèŠãªãã€ã³ãã¯ãäŸãšããŠFacebookã³ã³ãããŒã©ãŒã䜿çšãããSpring Securityã®ãŠãŒã¶ãŒã®çŽæ¥æ¿èªã§ãïŒãã¡ãããã³ã³ãã©ã€ã¢ã³ã¹ã確èªãããããã€ããŒã®APIããæš©å©ãååŸããåŸïŒã
@ RequestMapping(value = "/signin", params = "code") public ModelAndView signInAccessCode(@ RequestParam("code") String code, @ RequestParam("state") String state, HttpServletRequest request, HttpServletResponse response) throws Exception { String accessRequest = Utils.sendHttpRequest("GET", FACEBOOK_URL_ACCESS_TOKEN, new String[]{"client_id", "redirect_uri", "client_secret", "code"}, new String[]{FACEBOOK_API_KEY, FACEBOOK_URL_CALLBACK_SIGNIN, FACEBOOK_API_SECRET, code}); String token = Utils.parseURLQuery(accessRequest).get("access_token"); Map<String, Json> userInfoResponse = Json.read(Utils.sendHttpRequest("GET", FACEBOOK_URL_ME, new String[]{"access_token"}, new String[]{token})).asJsonMap(); FacebookAuthUser user = (FacebookAuthUser) authenticationDAO.findAuthUser(userInfoResponse.get("id").asString(), AuthenticationType.FACEBOOK); if (user == null) { //- ... return new ModelAndView(new RedirectView("/signin", true, true, false)); } else { if (!token.equals(user.getToken())) { user.setToken(token); user = (FacebookAuthUser) authenticationDAO.put(user); } Authentication authentication = customAuthenticationProvider.trust(user); if (state.equalsIgnoreCase("autosignin")) customRememberMeService.onLoginSuccess(request, response, authentication); else customRememberMeService.logout(request, response, authentication); // RememberMe return new ModelAndView(new RedirectView("/signin.complete", true, true, false)); } }
ããã§ãèªåãã°ã€ã³ã®ãã§ãã¯ããã¯ã¹ãéžæãããç¶æ ã§ãã¯ã©ã€ã¢ã³ãã¯èªåçã«ãã°ã€ã³ãããŸãããããã£ãŠããã§ãã¯ããŒã¯ããªãå ŽåãRememberMeãµãŒãã¹ã®ãã°ã¢ãŠãã¡ãœãããåŒã³åºããšãCookieãæ¶å»ãããŸãïŒä»ã«äœãè¡ãããŸããïŒãã¡ãªã¿ã«ãã/ãã°ã¢ãŠãããªã³ã¯ãã¯ãªãã¯ãããšãèªèšŒãåé€ãããCookieãèªåçã«ã¯ãªã¢ãããŸããããã¯ãäžèšã®Spring Securityæ§æã®å¯Ÿå¿ããè¡ã«ãã£ãŠæäŸãããŸãããã®ã¡ãœããã®äœ¿çšã¯ãæšæºã®æ¿èªã®ããã«ããã蟌ããããšãã§ããŸãããã§ãã¯ã«åæ ŒããåŸïŒããŒãã«ã§ãŠãŒã¶ãŒãèŠã€ãããã¹ã¯ãŒãããã·ã¥ã調æŽãããªã©ïŒãæåã§æ¿èªããŸãã
Authentication authentication = customAuthenticationProvider.trust(user); if (autosignin) customRememberMeService.onLoginSuccess(request, response, authentication); else customRememberMeService.logout(request, response, authentication);
䜿çšæ¹æ³ã«éãã¯ãããŸãããå¯äžã®éãã¯ãRememberMeã¡ã«ããºã ãããªã¬ãŒããããšãç¡é¢ä¿ãªãã§ãã¯ãè¡ãããªãããšã§ããå®éãTokenBasedRememberMeServicesãµãŒãã¹ã®æäœãšå®å šã«äžèŽããŸãã
ããã«ãæ¿èªã®äœ¿çšã¯éåžžã®Spring SecurityããŒã«ã®äœ¿çšã«äŒŒãŠããŸãããå¯äžã®éãã¯@Securedã¢ãããŒã·ã§ã³ïŒãCUSTOM_ROLEãïŒã䜿çšã§ããªãããšã§ããããã¯æšæºããŒã«çšã«èšèšãããŠããŸãïŒãã ããããããåå®çŸ©ããããã®ã¡ã«ããºã ãããããã§ãããç§ã¯å ¥ããŸããã§ããïŒãããããSpring Securityã«ã¯å¥ã®ã¡ã«ããºã ããããŸããåãã¢ãããŒã·ã§ã³@PreAuthorizeã@PostFilterïŒ@PreAuthorizeïŒ "hasRoleïŒ 'ADMINISTRATOR'ïŒ"ïŒã@ PreAuthorizeïŒ "hasRoleïŒ{'CUSTOMER'ã 'ADMINISTRATOR'}ïŒ"ïŒïŒãããã¯ãsecurityïŒglobal-method-securityãã©ã¡ãŒã¿ãŒã®Spring Securityæ§æã§ã®ã¿æå®ããå¿ èŠããããŸãã
åæ§ã«ããã¥ãŒïŒJSPå ïŒã§Spring Securityã®æ©èœãå©çšã§ããŸããäŸïŒ
<%@ taglib prefix="core" uri="http://java.sun.com/jsp/jstl/core" %> <%@ taglib prefix="sec" uri="http://www.springframework.org/security/tags" %> ... <sec:authorize access="isAuthenticated()"> <div id="userBox"> <span>Welcome, <sec:authentication property="principal.user.firstName"/>!</span> </div> </sec:authorize>
ãã®ãããªæ§é ã«ãããã¢ãã«ãã³ã³ãããŒã©ãŒãããã¥ãŒã«è»¢éããã«ãã¢ãã«ããã¥ãŒã«åé€ããã¡ã«ããºã ããã®ãŸãŸã«ããããšãã§ããŸãïŒããèªäœã¯DAOã®ã¢ãã«ã«é©çšãããŸãïŒãjspããŒãžã§jsp ã¹ã¯ãªããã¬ããã
䜿çšããããšãã§ããŸãïŒã¹ã¯ãªããã¬ããã®äœ¿çšã«ã¯å€ãã®æµãããŸãããäž»ã«ãbean-godãCaesar-cesareanããšããäœçœ®ã®ãããããã°ã©ããŒã¯ããã°ã©ãã³ã°ã«åŸäºããŠãããã¬ã€ã¢ãŠãããã³/ãŸãã¯ãã¶ã€ããŒã¯èšèšäžã§ã;ãããããã¯è°è«ã®äœå°ã¯ãããŸãããç§ã¯å人çã«ã¯ãããã®æŠå¿µãæ¯æããŠããŸãã-ã¯ããããã¯ããæã«ã¯éåžžã«äŸ¿å©ã§ãïŒïŒ
<%@ page import="org.springframework.security.core.context.SecurityContextHolder" %> <%@ page import="myproject.auth.AuthUser" %> <% Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal(); AuthUser authUser = null; if (!(principal instanceof String)) authUser = (AuthUser) principal; %> ... <input type="text" <%= authUser == null ? "" : "disabled=\"disabled\"" %> name="your_name" value="<%= authUser == null ? "" : authUser.getUser().getFirstName()%>"/> ... <% if (authUser == null) { %> <div id="recaptcha_widget"> <div id="recaptchaContainer"> ... </div> </div> <% } %>
æå®ãããããŒãžã³ãŒãã¯ãã»ãã¥ãªãã£ã®ã³ã³ããã¹ãã䜿çšããå¯èœæ§ã®ã¿ãåæ ããŸãããããŒãžã®ããžãã¯ã®æææ§ãè£ ããŸãã
èªèšŒãªããžã§ã¯ããšãã®ãã©ã¡ãŒã¿ãŒïŒããªã³ã·ãã«ãªããžã§ã¯ãïŒéã®é 延äŸåã«èµ·å ããããã«ããã¯ã«çŠç¹ãåœãŠãããšæããŸãããŠãŒã¶ãŒãã£ãŒã«ãïŒgetUserïŒïŒã¡ãœãããåŒã³åºãïŒãå«ãŸããŠãããããå€æŽãè¡ããªããšãããŒãžã³ãŒãã®äž¡æ¹ã®éšåã§ã©ã³ã¿ã€ã äŸå€ãçºçããŸããã¹ãŠã®ãã£ãŒã«ããnullã§åããããããã©ã«ãã®ãªããžã§ã¯ããOpenSessionInViewãã¿ãŒã³ã®äœ¿çšãã®å ŽåãäŸåãªããžã§ã¯ãã®è¿œå ã®ããŒããªãã§ã¯ãããã§ã®HTTPã»ãã·ã§ã³ã¯ç°ãªãããã圹ã«ç«ã¡ãŸããããããã£ãŠãããŒããããšããã«äŸåãªããžã§ã¯ããããŒãããå¿ èŠããããŸãããããã¯é 延æ¥ç¶ãå²ãåœãŠãããåå ãšãªã£ãã¢ãããŒããšççŸããŸã-ãªããžã§ã¯ããããŒããããäŸåãªããžã§ã¯ããå€æŽããŠãããŒãããããªããžã§ã¯ãã¯æŽæ°ãããŸããããã®å ŽåãEAGERæ¥ç¶ã確ç«ããæ¹ãç°¡åã§ããäžè¬çã«äœ¿çšãããsessionFactory.getCurrentSessionïŒïŒãæ°ããã»ãã·ã§ã³ã®éå§ã§çœ®ãæããããšã«ãããauthenticationDAOã§ããã決å®ããŸããïŒSessionFactoryUtils.openSessionïŒsessionFactoryïŒããããããããã¯ã¡ã¢ãªã®é¢ã§æãçµæžçãªãœãªã¥ãŒã·ã§ã³ã§ã¯ãããŸããããç§ã¯ãŸã ãã®è³ªåãããŠããªãããããã®ãããã¯ãæãäžããŠããŸãããçŸåšã®ã»ãã·ã§ã³ã®ååšã®ãã§ãã¯ãèšå®ããããšã§ããã£ã«ã¿ãŒãŸãã¯OpenSessionInViewã€ã³ã¿ãŒã»ãã¿ãŒãæåŠããŠãå®éã«ãã®äœæ¥ã眮ãæããããšãã§ãããšæããŸãã
ãã®ããã¹ãã¯å¿ èŠä»¥äžã®ãã®ã§ããããšãå€æããŸããã確ãã«ç©è°ããããããã誀ã£ãç¬éãããããŸãããèããããã¡ã«ããºã ãå®è£ ããéã«ç§ãééããå°é£ã®è§£æ±ºçãåæ ããããšããŸããã