package cn.com.jusesgod.domain.security;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Transient;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
@Entity
public class Account implements UserDetails{
/**
*
*/
private static final long serialVersionUID = 5275764647347461532L;
private String username; //用户名
private String password; //密码
private boolean enable; //是否可用
private Set grantedAuthorities; //表示用户所拥有的权限
private int total; //玩这个游戏的总局数
private int win; //赢的局数
private int lose; //输的局数
private int flee; //逃走的局数
public Account(){}
public Account(String username,String password){
this.username = username;
this.password = password;
this.total = 0;
this.win = 0;
this.lose = 0;
this.flee = 0;
}
public Account(String username,String password,int total,int win,int lose,int flee, Collection authorities){
this.username = username;
this.password = password;
this.total = total;
this.win = win;
this.lose = lose;
this.flee = flee;
this.enable = true;
grantedAuthorities = new HashSet();
for(GrantedAuthority t : authorities){
grantedAuthorities.add(new Authorities(this.username,t.getAuthority()));
}
}
public void strat(){
total += 1;
}
public void setFlee(int flee) {
this.flee = flee;
}
public void setLose(int lose) {
this.lose = lose;
}
public void setTotal(int total) {
this.total = total;
}
public void setWin(int win) {
this.win = win;
}
public void win(){
win += 1;
}
public void lose(){
lose += 1;
}
public void flee(){
flee += 1;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Id
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getTotal() {
return total;
}
public int getWin() {
return win;
}
public int getLose() {
return lose;
}
public int getFlee() {
return flee;
}
@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.EAGER) //FetchType.EAGER表示立刻加载
@JoinTable(name="authorities",
joinColumns=@JoinColumn(name="username"))
public Set getGrantedAuthorities() {
return grantedAuthorities;
}
@Transient
public Set getAuthorities() {
Set ga = new HashSet();
for(Authorities temp : grantedAuthorities){
ga.add(temp);
}
return ga;
}
public void setGrantedAuthorities(Set authorities) {
this.grantedAuthorities = authorities;
}
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
@Transient
public boolean isAccountNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Transient
public boolean isAccountNonLocked() {
// TODO Auto-generated method stub
return true;
}
@Transient
public boolean isCredentialsNonExpired() {
// TODO Auto-generated method stub
return true;
}
@Transient
public boolean isEnabled() {
return enable;
}
}
package cn.com.jusesgod.domain.security;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import org.springframework.security.core.GrantedAuthority;
@Entity
@IdClass(AuthoritiesPK.class)
public class Authorities implements GrantedAuthority {
private String username;
private String authority;
public Authorities(){}
public Authorities(String username,String authority){
this.username = username;
this.authority = authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
@Id
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
@Id
public String getAuthority() {
return authority;
}
}
package cn.com.jusesgod.domain.security;
import java.io.Serializable;
import javax.persistence.Embeddable;
@Embeddable
public class AuthoritiesPK implements Serializable {
private String username;
private String authority;
public AuthoritiesPK(){}
public AuthoritiesPK(String username,String authority){
this.username = username;
this.authority = authority;
}
public void setAuthority(String authority) {
this.authority = authority;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getAuthority() {
return authority;
}
}
springSecurityFilterChain
org.springframework.web.filter.DelegatingFilterProxy
springSecurityFilterChain
/*
xmlns:beans="http://www.springframework.org/schema/beans"
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.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
xmlns:security="http://www.springframework.org/schema/security"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
class="org.springframework.security.web.authentication.AuthenticationProcessingFilterEntryPoint">
package cn.com.jusesgod.authentication.provider;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
import org.springframework.security.authentication.dao.SaltSource;
import org.springframework.security.authentication.encoding.PasswordEncoder;
import org.springframework.security.authentication.encoding.PlaintextPasswordEncoder;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.util.Assert;
public class MyDaoAuthenticationProvider extends
AbstractUserDetailsAuthenticationProvider {
private PasswordEncoder passwordEncoder = new PlaintextPasswordEncoder();
private SaltSource saltSource;
private UserDetailsService userDetailsService;
private boolean includeDetailsObject = true;
//~ Methods ========================================================================================================
protected void additionalAuthenticationChecks(UserDetails userDetails,
UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
Object salt = null;
if (this.saltSource != null) {
salt = this.saltSource.getSalt(userDetails);
}
if (authentication.getCredentials() == null) {
logger.debug("Authentication failed: no credentials provided");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
includeDetailsObject ? userDetails : null);
}
String presentedPassword = authentication.getCredentials().toString();
logger.debug("presentedPassword:" + presentedPassword);
logger.debug("userDetails.getPassword():" + userDetails.getPassword());
System.out.println(presentedPassword);
if (!passwordEncoder.isPasswordValid(userDetails.getPassword(), presentedPassword, salt)) {
logger.debug("Authentication failed: password does not match stored value");
throw new BadCredentialsException(messages.getMessage(
"AbstractUserDetailsAuthenticationProvider.badCredentials", "Bad credentials"),
includeDetailsObject ? userDetails : null);
}
}
protected void doAfterPropertiesSet() throws Exception {
Assert.notNull(this.userDetailsService, "A UserDetailsService must be set");
}
protected final UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication)
throws AuthenticationException {
UserDetails loadedUser;
try {
loadedUser = this.getUserDetailsService().loadUserByUsername(username);
}
catch (DataAccessException repositoryProblem) {
throw new AuthenticationServiceException(repositoryProblem.getMessage(), repositoryProblem);
}
if (loadedUser == null) {
throw new AuthenticationServiceException(
"UserDetailsService returned null, which is an interface contract violation");
}
return loadedUser;
}
/**
* Sets the PasswordEncoder instance to be used to encode and validate passwords.
* If not set, {@link PlaintextPasswordEncoder} will be used by default.
*
* @param passwordEncoder The passwordEncoder to use
*/
public void setPasswordEncoder(PasswordEncoder passwordEncoder) {
this.passwordEncoder = passwordEncoder;
}
protected PasswordEncoder getPasswordEncoder() {
return passwordEncoder;
}
/**
* The source of salts to use when decoding passwords. null
* is a valid value, meaning the DaoAuthenticationProvider
* will present null
to the relevant PasswordEncoder
.
*
* @param saltSource to use when attempting to decode passwords via the PasswordEncoder
*/
public void setSaltSource(SaltSource saltSource) {
this.saltSource = saltSource;
}
protected SaltSource getSaltSource() {
return saltSource;
}
public void setUserDetailsService(UserDetailsService userDetailsService) {
this.userDetailsService = userDetailsService;
}
protected UserDetailsService getUserDetailsService() {
return userDetailsService;
}
protected boolean isIncludeDetailsObject() {
return includeDetailsObject;
}
/**
* Determines whether the UserDetails will be included in the extraInformation field of a
* thrown BadCredentialsException. Defaults to true, but can be set to false if the exception will be
* used with a remoting protocol, for example.
*
* @deprecated use {@link org.springframework.security.authentication.ProviderManager#setClearExtraInformation(boolean)}
*/
public void setIncludeDetailsObject(boolean includeDetailsObject) {
this.includeDetailsObject = includeDetailsObject;
}
}
package cn.com.jusesgod.service.impl;
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 org.springframework.context.ApplicationContextException;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.support.JdbcDaoSupport;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.util.Assert;
import cn.com.jusesgod.domain.security.Account;
/**
* UserDetailsServiceRetrieves implementation which retrieves the user details
* (username, password, enabled flag, and authorities) from a database using JDBC queries.
* UserDetailsServiceRettrieves
* 实现了如何去得到用用户的信息(username,password,enabled flag,和authorite)通过JDBC查询获取数据源
*
* Default Schema
* 默认的模式
* A default database schema is assumed, with two tables "users" and "authorities".
* 一个默认的数据模式被设定,有两个表"user"和"authorities"
* The Users table
* User表
* This table contains the login name, password and enabled status of the user.
*
*
* Column
* username
* password
* enabled
*
*
* The Authorities Table
* Authorities表
*
* Column
* username
* authority
*
*
* If you are using an existing schema you will have to set the queries usersByUsernameQuery and
* authoritiesByUsernameQuery to match your database setup
* 如果你使用一个存在的模式,你必须设置查询方法"usersByUsernameQuery"和"authoritiesByUsernameQuery"去适应你的数据源设置
* (see {@link #DEF_USERS_BY_USERNAME_QUERY} and {@link #DEF_AUTHORITIES_BY_USERNAME_QUERY}).
* 查看这两个变量会有帮助
*
*
* In order to minimise backward compatibility issues, this implementation doesn't recognise the expiration of user
* accounts or the expiration of user credentials. However, it does recognise and honour the user enabled/disabled
* column. This should map to a boolean type in the result set (the SQL type will depend on the
* database you are using). All the other columns map to Strings.
* 为了尽量减少向后兼容性的问题,这个实现不关心用户账户的期限或者用户证书的期限。而只关心注意用户是否可用(enable/disable列),这需要设置成一个
* boolean的类型在返回的设置里(在数据库保存的SQL属性取决于你的数据库)所有其他的属性使用String类型
*
*
Group Support
* 组权限支持
* Support for group-based authorities can be enabled by setting the enableGroups property to true
* (you may also then wish to set enableAuthorities to false to disable loading of authorities
* directly). With this approach, authorities are allocated to groups and a user's authorities are determined based
* on the groups they are a member of. The net result is the same (a UserDetails containing a set of
* GrantedAuthoritys is loaded), but the different persistence strategy may be more suitable for the
* administration of some applications.
*
* 对于支持组权限,我们需要设置enableGroups属性为true(你应当还希望去设置enableAuthorities为false去阻止导入authorities表中的权限设置)
* 通过这种方法,权限被分成一组一组的,并且用户的权限被通过组的方法确定他们归属于那一个权限组。网络要求同样的(一个UserDetails包含
* 一个GrantedAuthority的设置被读取),但是不同的应用可能需要不同的持久化策略。
*
* When groups are being used, the tables "groups", "group_members" and "group_authorities" are used. See
* {@link #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY} for the default query which is used to load the group authorities.
* Again you can customize this by setting the groupAuthoritiesByUsernameQuery property, but the format of
* the rows returned should match the default.
* 当组权限被使用,表groups,group_members和group_authorities也被使用。参看DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY属性,了解
* 默认的组权限查询语句。
* 同样,你可以去自定义这个属性通过设置groupAuthoritiesByUsernameQuery属性,但是返回的结果列会被格式化成默认的形式。
*
* @author Ben Alex
* @author colin sampaleanu
* @author Luke Taylor
*/
public class AccountJDBCImpl extends JdbcDaoSupport implements UserDetailsService {
// ~ Static fields/initializers =====================================================================================
public static final String DEF_USERS_BY_USERNAME_QUERY =
"select username,password,enable " +
"from Account " +
"where username = ?";
public static final String DEF_AUTHORITIES_BY_USERNAME_QUERY =
"select username,authority " +
"from Authorities " +
"where username = ?";
public static final String DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY =
"select g.id, g.group_name, ga.authority " +
"from groups g, group_members gm, group_authorities ga " +
"where gm.username = ? " +
"and g.id = ga.group_id " +
"and g.id = gm.group_id";
//~ Instance fields ================================================================================================
protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
private String authoritiesByUsernameQuery;
private String groupAuthoritiesByUsernameQuery;
private String usersByUsernameQuery;
private String rolePrefix = "";
private boolean usernameBasedPrimaryKey = true;
private boolean enableAuthorities = true;
private boolean enableGroups = false;
//~ Constructors ===================================================================================================
public AccountJDBCImpl() {
usersByUsernameQuery = DEF_USERS_BY_USERNAME_QUERY;
authoritiesByUsernameQuery = DEF_AUTHORITIES_BY_USERNAME_QUERY;
groupAuthoritiesByUsernameQuery = DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY;
}
//~ Methods ========================================================================================================
/**
* Allows subclasses to add their own granted authorities to the list to be returned in the UserDetails.
* 允许子类添加他们自己的授权权限到列表里,在UserDetails里面被返回。
*
* @param username the username, for use by finder methods
* @param authorities the current granted authorities, as populated from the authoritiesByUsername
* mapping
*/
protected void addCustomAuthorities(String username, List authorities) {
}
public String getUsersByUsernameQuery() {
return usersByUsernameQuery;
}
protected void initDao() throws ApplicationContextException {
//确保两个权限模式必有一个在使用
Assert.isTrue(enableAuthorities || enableGroups, "Use of either authorities or groups must be enabled");
}
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException, DataAccessException {
List users = loadUsersByUsername(username);
if (users.size() == 0) {
logger.debug("Query returned no results for user '" + username + "'");
throw new UsernameNotFoundException(
messages.getMessage("JdbcDaoImpl.notFound", new Object[]{username}, "Username {0} not found"), username);
}
UserDetails user = users.get(0); // contains no GrantedAuthority[]
Set dbAuthsSet = new HashSet();
if (enableAuthorities) {
dbAuthsSet.addAll(loadUserAuthorities(user.getUsername()));
}
if (enableGroups) {
dbAuthsSet.addAll(loadGroupAuthorities(user.getUsername()));
}
List dbAuths = new ArrayList(dbAuthsSet);
addCustomAuthorities(user.getUsername(), dbAuths);
if (dbAuths.size() == 0) {
logger.debug("User '" + username + "' has no authorities and will be treated as 'not found'");
throw new UsernameNotFoundException(
messages.getMessage("JdbcDaoImpl.noAuthority",
new Object[] {username}, "User {0} has no GrantedAuthority"), username);
}
System.out.println("dbAuths:" + dbAuths.get(0).getAuthority());
return createUserDetails(username, user, dbAuths);
}
/**
* Executes the SQL usersByUsernameQuery and returns a list of UserDetails objects.
* There should normally only be one matching user.
*/
protected List loadUsersByUsername(String username) {
return getJdbcTemplate().query(usersByUsernameQuery, new String[] {username}, new RowMapper() {
public UserDetails mapRow(ResultSet rs, int rowNum) throws SQLException {
String username = rs.getString(1);
String password = rs.getString(2);
return new Account(username,password,0,0,0,0,new HashSet());
}
});
}
/**
* Loads authorities by executing the SQL from authoritiesByUsernameQuery.
*
* @return a list of GrantedAuthority objects for the user
*/
protected List loadUserAuthorities(String username) {
return getJdbcTemplate().query(authoritiesByUsernameQuery, new String[] {username}, new RowMapper() {
public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
String roleName = rolePrefix + rs.getString(2);
logger.debug("row authorities:" + roleName + " to " + rs.getString(1));
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
return authority;
}
});
}
/**
* Loads authorities by executing the SQL from groupAuthoritiesByUsernameQuery.
*
* @return a list of GrantedAuthority objects for the user
*/
protected List loadGroupAuthorities(String username) {
return getJdbcTemplate().query(groupAuthoritiesByUsernameQuery, new String[] {username}, new RowMapper() {
public GrantedAuthority mapRow(ResultSet rs, int rowNum) throws SQLException {
String roleName = getRolePrefix() + rs.getString(3);
GrantedAuthorityImpl authority = new GrantedAuthorityImpl(roleName);
return authority;
}
});
}
/**
* Can be overridden to customize the creation of the final UserDetailsObject which is
* returned by the loadUserByUsername method.
*
* @param username the name originally passed to loadUserByUsername
* @param userFromUserQuery the object returned from the execution of the
* @param combinedAuthorities the combined array of authorities from all the authority loading queries.
* @return the final UserDetails which should be used in the system.
*/
protected UserDetails createUserDetails(String username, UserDetails userFromUserQuery,
List combinedAuthorities) {
String returnUsername = userFromUserQuery.getUsername();
if (!usernameBasedPrimaryKey) {
returnUsername = username;
}
logger.debug("username = " + returnUsername);
logger.debug("password = " + userFromUserQuery.getPassword());
return new Account(returnUsername, userFromUserQuery.getPassword(), 0,
0, 0, 0,combinedAuthorities);
}
/**
* Allows the default query string used to retrieve authorities based on username to be overridden, if
* default table or column names need to be changed. The default query is {@link
* #DEF_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query, ensure that all returned columns are mapped
* back to the same column names as in the default query.
*
* @param queryString The SQL query string to set
*/
public void setAuthoritiesByUsernameQuery(String queryString) {
authoritiesByUsernameQuery = queryString;
}
protected String getAuthoritiesByUsernameQuery() {
return authoritiesByUsernameQuery;
}
/**
* Allows the default query string used to retrieve group authorities based on username to be overridden, if
* default table or column names need to be changed. The default query is {@link
* #DEF_GROUP_AUTHORITIES_BY_USERNAME_QUERY}; when modifying this query, ensure that all returned columns are mapped
* back to the same column names as in the default query.
*
* @param queryString The SQL query string to set
*/
public void setGroupAuthoritiesByUsernameQuery(String queryString) {
groupAuthoritiesByUsernameQuery = queryString;
}
/**
* Allows a default role prefix to be specified. If this is set to a non-empty value, then it is
* automatically prepended to any roles read in from the db. This may for example be used to add the
* ROLE_ prefix expected to exist in role names (by default) by some other Spring Security
* classes, in the case that the prefix is not already present in the db.
*
* @param rolePrefix the new prefix
*/
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
protected String getRolePrefix() {
return rolePrefix;
}
/**
* If true
(the default), indicates the {@link #getUsersByUsernameQuery()} returns a username
* in response to a query. If false
, indicates that a primary key is used instead. If set to
* true
, the class will use the database-derived username in the returned UserDetails
.
* If false
, the class will use the {@link #loadUserByUsername(String)} derived username in the
* returned UserDetails
.
*
* @param usernameBasedPrimaryKey true
if the mapping queries return the username String
,
* or false
if the mapping returns a database primary key.
*/
public void setUsernameBasedPrimaryKey(boolean usernameBasedPrimaryKey) {
this.usernameBasedPrimaryKey = usernameBasedPrimaryKey;
}
protected boolean isUsernameBasedPrimaryKey() {
return usernameBasedPrimaryKey;
}
/**
* Allows the default query string used to retrieve users based on username to be overridden, if default
* table or column names need to be changed. The default query is {@link #DEF_USERS_BY_USERNAME_QUERY}; when
* modifying this query, ensure that all returned columns are mapped back to the same column names as in the
* default query. If the 'enabled' column does not exist in the source database, a permanent true value for this
* column may be returned by using a query similar to
*
* "select username,password,'true' as enabled from users where username = ?"
*
*
* @param usersByUsernameQueryString The query string to set
*/
public void setUsersByUsernameQuery(String usersByUsernameQueryString) {
this.usersByUsernameQuery = usersByUsernameQueryString;
}
protected boolean getEnableAuthorities() {
return enableAuthorities;
}
/**
* Enables loading of authorities (roles) from the authorities table. Defaults to true
*/
public void setEnableAuthorities(boolean enableAuthorities) {
this.enableAuthorities = enableAuthorities;
}
protected boolean getEnableGroups() {
return enableGroups;
}
/**
* Enables support for group authorities. Defaults to false
* @param enableGroups
*/
public void setEnableGroups(boolean enableGroups) {
this.enableGroups = enableGroups;
}
}