源码
下载
半成品源码下载地址: http://pan.baidu.com/s/1bn91N6B
文件结构
|
开发平台选用的是Eclipse+Maven+tomcat. 项目的依赖请查看pom.xml。
配置web.xml
将Spring Security filter至于struts filter之前,让SS可以多所有的URL进行保护。
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/user/*</url-pattern>
<url-pattern>/auth/*</url-pattern>
<url-pattern>/register/*</url-pattern>
</filter-mapping>
配置Spring Security
让SS对/auth/login*和/register/**放行。配置Authentication-Provider使用自己定义的UserService, 并使用PasswordEncoder对password进行加密。
<s:http use-expressions="true" authentication-manager-ref="AuthManager">
<s:intercept-url pattern="/auth/login*" access="permitAll()" />
<s:intercept-url pattern="/register/**" access="permitAll()" />
<s:intercept-url pattern="/**" access="isAuthenticated()" />
<s:form-login login-page='/auth/login'
default-target-url="/user/profile" login-processing-url="/spring_security_check"
authentication-failure-url="/auth/login?error" password-parameter="password" username-parameter="username" />
<s:logout invalidate-session="true" logout-success-url="/auth/login?logout" logout-url="/spring_logout" />
</s:http>
<s:authentication-manager id="AuthManager">
<s:authentication-provider ref="daoAuthProvider">
</s:authentication-provider>
</s:authentication-manager>
<bean id="daoAuthProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<property name="userDetailsService" ref="myUserAuthService" /> <!-- From business. We implement it. -->
<property name="passwordEncoder" ref="passwordEncoder" />
</bean>
<bean id="myUserAuthService" class="com.xpbug.demo.auth.UserService">
<!-- Use mybatis dao -->
<property name="userDao" ref="UserDao"></property>
</bean>
<bean id="passwordEncoder" class="org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder">
<constructor-arg name="strength" value="10"></constructor-arg>
</bean>
其中UserDao在applicationContext-mybatis.xml中有定义。
com.xpbug.demo.auth.UserService的实现为:
public class UserService implements UserDetailsService {
private UserDao userDao;
private Logger logger = LoggerFactory.getLogger(UserService.class);
/* (non-Javadoc)
* @see org.springframework.security.core.userdetails.UserDetailsService#loadUserByUsername(java.lang.String)
*/
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.xpbug.demo.model.User user = this.userDao.getLoginById(username);
List<String> roles = user.getRoles();
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String r:roles) {
logger.info("Grant role: {}", r);
authorities.add(new SimpleGrantedAuthority(r));
}
User sUser = new User(user.getUserId(), user.getPassword(), authorities);
return sUser;
}
// Getters and Setters...
}
在UserService中,我们使用UserDao获取数据库中的用户,然后将数据库取出的用户,封装成SS所需要的形式。
这样,登录部分完成了。接下来,我们来定义Struts的Action。
Struts
在Struts中,我将定义以下几个URI:
/auth/login 展示登录页面
/auth/logout 注销,然后转登录页面。
/register/form 展示注册页面
/register/do 处理register form POST。然后chain to auto login action.
/register/autoLogin 承接/register/do, 进行自动登录,成功以后重定向到/user/profile
/user/profile 一个受SS保护的页面。
struts.xml:
<constant name="struts.action.extension" value="" />
<package name="auth" extends="abstract" namespace="/auth">
<action name="login" class="LoginPageAction">
<result name="success">/WEB-INF/jsp/login.jsp</result>
</action>
<action name="logout">
<result name="success" type="redirect">/spring_logout</result>
</action>
</package>
<package name="register" extends="abstract" namespace="/register">
<action name="form" class="RegisterAction">
<result>/WEB-INF/jsp/register.jsp</result>
</action>
<action name="do" class="RegisterAction" method="register">
<result name="success" type="chain">
<param name="actionName">autoLogin</param>
<param name="method">login</param>
</result>
</action>
<action name="autoLogin" class="AutoLoginAction" method="login">
<result type="redirect">/user/profile</result>
</action>
</package>
<package name="user" extends="abstract" namespace="/user">
<action name="profile">
<result name="success">/WEB-INF/jsp/test.jsp</result>
</action>
</package>
其它Action不表,重点说下掌管注册和自动登录的两个Action。
RegisterAction
服务于注册的Action需要接收用户id和密码。此外,它还需要userService服务于用户创建,util服务于encode password。util的定义可以在applicationContext-business.xml中找到,它使用了Spring Security提供的password encoder,和登录时使用的encoder是同一个bean。
用户创建成功以后,将使用Chain Result,转到AutoLoginAction。
public class RegisterAction extends ActionSupport {
private static final long serialVersionUID = -3114254552070420296L;
private UserService userService;
private Util util;
private String uid;
private String password;
private String repassword;
public String register() {
if (password.equals(repassword)) {
User user = new User();
user.setUserId(uid);
user.setPassword(util.encodePassword(password));
userService.registerUser(user);
}
return "success";
}
// Getters and Setters...
}
AutoLoginAction
因为AutoLoginAction是由RegisterAction的result Chain过来的,所以可以接收RegisterAction相同的parameters。我们让它接收uid和password两个参数。
此外,它还需要用到登录时使用的AuthenticationManager, AuthenticationManager将会被Spring注入。
在login函数执行完毕以后,Session中就存在了SS所需要的所有认证信息。后面的URL就不需要再进行认证了。
AutoLoginAction成功以后,会重定向到/user/profile页面。
public class AutoLoginAction {
private String uid;
private String password;
private AuthenticationManager authenticationManager;
public String login() {
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(uid, password);
HttpServletRequest request = ServletActionContext.getRequest();
// generate session if one doesn't exist
request.getSession();
token.setDetails(new WebAuthenticationDetails(request));
Authentication authenticatedUser = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
return "success";
}
// Getters and Setters ...
}
Bean注册
关于Struts, mybatis和business各类bean的注册,不多废话。可以查看源代码。
运行
请先安装mysql,然后使用schema.sql创建数据库。
在applicationContext-mybatis.xml中修改datasource的配置。
编译打包成demo.war. 直接部署到tomcat中。
可访问URL: http://localhost:8080/demo/auth/login