Spring security 使用Spring Security访问CAS发布的属性

Spring security 使用Spring Security访问CAS发布的属性,spring-security,cas,Spring Security,Cas,我很难弄清楚如何使用SpringSecurity和SpringMVC访问servlet中CAS发布的属性。传统上,在无Spring实现中,我会这样做 public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Gets the user ID from CAS AttributePrincipal princi

我很难弄清楚如何使用SpringSecurity和SpringMVC访问servlet中CAS发布的属性。传统上,在无Spring实现中,我会这样做

public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException
{
   // Gets the user ID from CAS
   AttributePrincipal principal = (AttributePrincipal) request.getUserPrincipal();
   final Map<String, Object> attributes = principal.getAttributes();
   String userId = (String) attributes.get("userid");

   // ...
}

然而,除了比以前的实现稍微长一点之外,似乎不可能支持从CAS映射多个属性(例如,如果CAS同时发布
firstName
lastName
属性)


有没有更好的方法来设置security context.xml以允许更轻松地访问这些属性,特别是当我想在web应用程序中使用多个属性时?

我想我已经找到了答案。除了将属性设置为权限之外(如果您使用这些属性来确定权限(即
hasAuthority('username')
),似乎唯一的其他方法是构建您自己的
UserDetails
UserDetailsService
类)

例如,
MyUser

package my.custom.springframework.security.userdetails;

import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

public class MyUser extends User
{
   private static final long serialVersionUID = 1L;

   private String id;
   private String lastName;
   private String firstName;

   public MyUser(
         String username,
         String password,
         String id,
         String lastName,
         String firstName,
         Collection<? extends GrantedAuthority> authorities)
   {
      super(username, password, authorities);
      this.id = id;
      this.lastName = lastName;
      this.firstName = firstName;
   }

   public String getId()
   {
      return id;
   }

   public String getLastName()
   {
      return lastName;
   }

   public String getFirstName()
   {
      return firstName;
   }
}
最后,我在我的
casAuthenticationProvider
中设置了
authenticationUserDetailsService
来使用这个类,并从我的容器中传入一个全局数据源(本例中为Tomcat 6):

。。。
...
<security:user-service id="userService">
  <security:user name="user" password="user" authorities="ROLE_ADMIN,ROLE_USER" />
</security:user-service>

<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
  <property name="authenticationUserDetailsService">
    <bean class="org.springframework.security.core.userdetails.UserDetailsByNameServiceWrapper">
      <constructor-arg ref="userService" />
    </bean>
  </property>
  <property name="serviceProperties" ref="serviceProperties" />
  <property name="ticketValidator">
    <bean class="org.jasig.cas.client.validation.Saml11TicketValidator">
      <constructor-arg value="https://localhost:8443/cas" />
    </bean>
  </property>
  <property name="key" value="casAuthProviderKey" />
</bean>
<bean id="casAuthenticationProvider" class="org.springframework.security.cas.authentication.CasAuthenticationProvider">
  <property name="authenticationUserDetailsService">
    <bean class="org.springframework.security.cas.userdetails.GrantedAuthorityFromAssertionAttributesUserDetailsService">
      <constructor-arg>
        <list>
          <value>userid</value>
        </list>
      </constructor-arg>
    </bean>
  </property>
  <property name="serviceProperties" ref="serviceProperties" />
  <property name="ticketValidator">
    <bean class="org.jasig.cas.client.validation.Saml11TicketValidator">
      <constructor-arg value="https://localhost:8443/cas" />
    </bean>
  </property>
  <property name="key" value="casAuthProviderKey" />
</bean>
@RequestMapping("/")
public String welcome(HttpServletRequest request)
{
   CasAuthenticationToken principal = (CasAuthenticationToken) request.getUserPrincipal();
   UserDetails userDetails = principal.getUserDetails();
   Collection<SimpleGrantedAuthority> authorities = (Collection<SimpleGrantedAuthority>) userDetails.getAuthorities();
   Iterator<SimpleGrantedAuthority> it = authorities.iterator();

   String userid = it.next().getAuthority();

   // ...
}
package my.custom.springframework.security.userdetails;

import java.util.Collection;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.User;

public class MyUser extends User
{
   private static final long serialVersionUID = 1L;

   private String id;
   private String lastName;
   private String firstName;

   public MyUser(
         String username,
         String password,
         String id,
         String lastName,
         String firstName,
         Collection<? extends GrantedAuthority> authorities)
   {
      super(username, password, authorities);
      this.id = id;
      this.lastName = lastName;
      this.firstName = firstName;
   }

   public String getId()
   {
      return id;
   }

   public String getLastName()
   {
      return lastName;
   }

   public String getFirstName()
   {
      return firstName;
   }
}
package my.custom.springframework.security.userdetails;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.sql.DataSource;

import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.cas.userdetails.AbstractCasAssertionUserDetailsService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

public final class MyUserDetailsService extends AbstractCasAssertionUserDetailsService
{
   public static final String DEF_USERS_BY_ID_QUERY = "select ?, id, last_name, first_name " +
         "from users " + "where id = ?";
   public static final String DEF_AUTHORITIES_BY_ID_QUERY = "select role " +
         "from roles join users on users.username = roles.username " +
         "where users.id = ?";

   private static final String NON_EXISTENT_PASSWORD_VALUE = "NO_PASSWORD";

   private JdbcTemplate jdbcTemplate;

   private String usersByIdQuery;
   private String authoritiesByIdQuery;

   public MyUserDetailsService(DataSource dataSource)
   {
      this.jdbcTemplate = new JdbcTemplate(dataSource);
      this.usersByIdQuery = DEF_USERS_BY_ID_QUERY;
      this.authoritiesByIdQuery = DEF_AUTHORITIES_BY_ID_QUERY;
   }

   protected MyUser loadUserDetails(Assertion assertion)
   {
      AttributePrincipal attributePrincipal = assertion.getPrincipal();
      String username = attributePrincipal.getName();
      String id = (String) attributePrincipal.getAttributes().get("userid");

      MyUser user = loadUser(username, id);

      Set<GrantedAuthority> dbAuthsSet = new HashSet<GrantedAuthority>();
      dbAuthsSet.addAll(loadUserAuthorities(id));
      List<GrantedAuthority> dbAuths = new ArrayList<GrantedAuthority>(dbAuthsSet);

      return createMyUser(username, user, dbAuths);
   }

   protected MyUser loadUser(String username, String id)
   {
      return jdbcTemplate.queryForObject(usersByIdQuery, new String[] { username, id },
            new RowMapper<MyUser>()
            {
               public MyUser mapRow(ResultSet rs, int rowNum) throws SQLException
               {
                  String username = rs.getString(1);
                  String id = rs.getString(2);
                  String lastName = rs.getString(3);
                  String firstName = rs.getString(4);
                  return new MyUser(username, NON_EXISTENT_PASSWORD_VALUE, id, lastName, firstName,
                        AuthorityUtils.NO_AUTHORITIES);
               }
            });
   }

   protected List<GrantedAuthority> loadUserAuthorities(String id)
   {
      return jdbcTemplate.query(authoritiesByIdQuery, new String[] { id },
            new RowMapper<GrantedAuthority>()
            {
               public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException
               {
                  // TODO Replace with rolePrefix variable
                  String roleName = "ROLE_" + rs.getString(1);
                  return new SimpleGrantedAuthority(roleName);
               }
            });
   }

   protected MyUser createMyUser(String username,
         MyUser userFromUserQuery, List<GrantedAuthority> combinedAuthorities)
   {
      return new MyUser(username, userFromUserQuery.getPassword(),
            userFromUserQuery.getId(), userFromUserQuery.getLastName(), userFromUserQuery.getFirstName(),
            combinedAuthorities);
   }
}
...
<property name="authenticationUserDetailsService">
  <bean class="my.custom.springframework.security.userdetails.MyUserDetailsService">
    <constructor-arg>
      <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/my/conn"/>
    </constructor-arg>
  </bean>
</property>
...