spring3.0 MVC笔记4-集成spring security3.1
1、下载spring security,集成下列jar包:
--spring-security-config-3.1.3.RELEASE.jar
--spring-security-core-3.1.3.RELEASE.jar
--spring-security-taglibs-3.1.3.RELEASE.jar
--spring-security-web-3.1.3.RELEASE.jar
2、配置web.xml中的filter
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
<filter-mapping>
<filter-name>springSecurityFilterChain</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
一定要写上filer-mapping,因为忘写filter-mapping程序根本不触发spring security的任何东西,也不报错,就是不干security的活。
3、修改log4j.properties增加下面行:
log4j.logger.org.springframework.security=DEBUG
以观察security的执行情况
4、在src下创建security.xml:
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.1.xsd">
<http auto-config="true" use-expressions="false">
<intercept-url pattern="/home" access="ROLE_TEST" />
</http>
</beans:beans>
把它加到context路径中
启动tomcat,报错:
No bean named 'org.springframework.security.authenticationManager' is defined: Did you forget to add a gobal <authentication-manager> element to your configuration (with child <authentication-provider> elements)? Alternatively you can use the authentication-manager-ref attribute on your <http> and <global-method-security> elements.
因为没有配置用户库<authentication-manager>
5、配置最简单的内存用户库<authentication-manager>
在上面security.xml中添加:
<user-service id="userService1">
<user name="habuma" password="letmein"
authorities="ROLE_SPITTER,ROLE_ADMIN,ROLE_TEST"/>
<user name="twoqubed" password="longhorns"
authorities="ROLE_SPITTER"/>
<user name="admin" password="admin"
authorities="ROLE_ADMIN"/>
</user-service>
<authentication-manager>
<authentication-provider user-service-ref="userService1" />
</authentication-manager>
注意角色名称一定要有ROLE_前缀,不用这个前缀需要改配置。
运行起来,访问http://t18:3000/s4/home,出现spring security自带的登陆界面;输入habuma letmein,登陆成功!
6、配置jdbc访问数据库用户
去掉上面5中的内容,加上:
<jdbc-user-service id="userService1"
data-source-ref="dataSource"
users-by-username-query=
"select logname,password,1 from users where logName=?"
authorities-by-username-query=
"select b.logName username,rolename from users_roles a,users b,roles c where a.userId=b.userId and a.roleId=c.roleId and b.logName=?" />
<authentication-manager>
<authentication-provider user-service-ref="userService1" />
</authentication-manager>
注意sql语句的写法:
--取用户:select logname,password,1 from users where logName=?一定要有1(SQLServer,其他数据库可取能为true);
--取角色:select b.logName username,rolename from users_roles a,users b,roles c where a.userId=b.userId and a.roleId=c.roleId and b.logName=?
用户名一定要用username的别名,否则取不到
运行起来,访问http://t18:3000/s4/home,出现spring security自带的登陆界面;输入test test,登陆成功!
当然,数据库中用户名test,密码test,角色ROLE_TEST
7、配置hibernate访问数据库用户
参照http://stackoverflow.com/questions/2683308/spring-security-3-database-authentication-with-hibernate
这里需要写一点代码。
a、写一个org.springframework.security.core.userdetails.User的构造器assembler bean:
@Service("assembler")
public class Assembler {
//@Transactional(readOnly = true)
User buildUserFromUserEntity(com.tdrc.common.beans.User userEntity) {
String username = userEntity.getLogName();
String password = userEntity.getPassword();
boolean enabled = true;//userEntity.isActive();
boolean accountNonExpired = true;//userEntity.isActive();
boolean credentialsNonExpired = true;//userEntity.isActive();
boolean accountNonLocked = true;//userEntity.isActive();
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (Object userrole : userEntity.getUserRoles()) {
UserRole ur = (UserRole)userrole;
authorities.add(new GrantedAuthorityImpl(ur.getId().getRole().getRoleName()));
}
User user = new User(username, password, enabled,
accountNonExpired, credentialsNonExpired, accountNonLocked, authorities);
return user;
}
}
b、实现org.springframework.security.core.userdetails.UserDetailsService接口的服务userDetailsService bean:
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired private com.tdrc.common.dao.IUserDao dao;
@Autowired private Assembler assembler;
//@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException {
UserDetails userDetails = null;
User userEntity = (User)dao.findObjectByHQL("from User u where u.logName='"+username+"'");
if (userEntity == null)
throw new UsernameNotFoundException("user not found");
return assembler.buildUserFromUserEntity(userEntity);
}
}
c、在security.xml中,用userDetailsService提供用户:
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<!-- password-encoder hash="md5"/ -->
</authentication-provider>
</authentication-manager>
d、配置事务,使得hibernate可用:
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<tx:method name="load*" propagation="REQUIRED" read-only="true" />
<tx:method name="build*" propagation="REQUIRED" read-only="true" />
<tx:method name="*" read-only="true" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:advisor
pointcut="execution(* *..UserDetailsService.*(..))"
advice-ref="txAdvice"/>
<aop:advisor
pointcut当"execution(* *..Assembler.*(..))"
advice-ref="txAdvice"/>
</aop:config>
运行起来,访问http://t18:3000/s4/home,出现spring security自带的登陆界面;输入test test,登陆成功!
依然,数据库中用户名test,密码test,角色ROLE_TEST。
8、修改默认登陆界面
security.xml中修改http配置,增加form-login属性
<http auto-config="true" use-expressions="false">
<form-login
login-processing-url="/j_spring_security_check"
login-page="/login"
authentication-failure-url="/login?login_error=t"/>
<intercept-url pattern="/home" access="ROLE_TEST"/>
<logout />
</http>
这里login-page和authentication-failure-url的/login指向一个spring mvc 控制器,它指向一个自定义登陆页面。
login-processing-url="/j_spring_security_check" 在《spring in action》第三版中写的是/static/j_spring_security_check
有的地方又说是/应用根/j_spring_security_check,折腾一上午,最后在我的环境里应该是/j_spring_security_check
自定义登陆页面就是一个form,用POST方法提交到/j_spring_security_check,用户名的name属性写成j-username,密码的name属性写成j-password即可。
<%@ taglib prefix="sf" uri="http://www.springframework.org/tags" %>
<sf:url var="authUrl"
value="/j_spring_security_check" />
<form method="post" class="signin" action="${authUrl}">
<li style="height:33px;list-style-type: none;">
<input type="text" name="j_username" class="Bboder"/>
</li>
<li style="height:33px;list-style-type: none;">
<input type="password" name="j_password" class="Bboder"/>
</li>
<li style="float:left"> <input type="submit" value="Submit" value="登录" type="image" src="images/lb.gif"/>
</li>
</form>
9、另注:在参考spring security tutorial时,它用的是logback日志系统,需要添加:
jcl-over-slf4j-1.6.1.jar
logback-classic-0.9.29.jar
logback-core-0.9.29.jar
slf4j-api-1.6.1.jar
并在src下创建logback.xml:
<configuration>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<logger name="org.springframework.security" level="DEBUG"/>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>