spring security

505 阅读5分钟
原文链接: m.blog.csdn.net

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="www.springframework.org/schema/bean…"
xmlns="www.springframework.org/schema/secu…"
xmlns:xsi="www.w3.org/2001/XMLSch…"
xsi:schemaLocation="www.springframework.org/schema/bean…
www.springframework.org/schema/bean…
www.springframework.org/schema/secu…
www.springframework.org/schema/secu…">
<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访问数据库用户

参照stackoverflow.com/questions/2…

这里需要写一点代码。
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="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>