正如标题所说,我正在开发一个从外部应用程序接收用户身份验证信息的Web应用程序。我的应用程序的弹簧控制器获取用户信息并将其存储在会话中。我想在Spring Security中对此用户进行身份验证,然后使用他的角色授予/拒绝对
等网址的访问权限<intercept-url pattern="/myprotectedpage*" access="hasRole('rightrole')" />
我阅读了一些关于PRE_AUTH_FILTER和UserDetailsService的教程,但我无法理解。 Spring Security的应用程序生命周期是什么?涉及哪些课程? 我需要一些完整的工作样本。
答案 0 :(得分:1)
有很多关于同样的东西,只需要谷歌正确。
无论如何,迄今为止我发现的最好的(几乎所有的春天)都是Krams,这是基本弹簧安全的一个。
http://krams915.blogspot.com/2010/12/spring-security-mvc-integration_18.html
对于实现UserDetailService,这里是链接
http://krams915.blogspot.in/2012/01/spring-security-31-implement_5023.html
其他一些人是:
修改强>
这是我自己的应用程序进行身份验证的方式(请注意,我不使用外部身份验证,我只是简单地从数据库获取详细信息,但我想这不应该是一个问题)。
我的security-context.xml
:
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/security"
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">
<global-method-security pre-post-annotations="enabled" jsr250-annotations="enabled" secured-annotations="enabled">
</global-method-security>
<http use-expressions="true">
<intercept-url pattern="/favicon.ico" access="permitAll" />
<intercept-url pattern="/static/**" access="permitAll"/>
<intercept-url pattern="/login.jsp*" access="permitAll"/>
<intercept-url pattern="/Admin/**" access="hasAnyRole('ROLE_SUPER_USER')"/>
<intercept-url pattern="/**" access="hasAnyRole('ROLE_USER','ROLE_SUPER_USER','ROLE_ADMIN'"/>
<form-login login-page="/login.jsp" authentication-failure-url="/login.jsp?login_error=1" />
<http-basic/>
<logout logout-success-url="/login.jsp"/>
<remember-me user-service-ref="loginService" /
</http>
<authentication-manager>
<authentication-provider user-service-ref="loginService">
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
<beans:bean id="loginService" class="com.indyaah.service.LoginService">
</beans:bean>
<beans:bean id="authService" class="com.indyaah.service.AuthService" />
</beans:beans>
现在你看到我已经指定了一个名为loginService
的bean作为我的身份验证提供程序,它是类com.indyaah.service.LoginService
的bean。
相同的代码是: Pl注意我已截断不必要的代码
package com.indyaah.service;
..
@Service
public class LoginService implements UserDetailsService {
....
/**
* Implementation for custom spring security UserDetailsService
*/
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
logger.debug("Inside get member by username");
if (userName != null) {
Member memberVO = memberMapper.getMemberByUsername(userName);
if (memberVO != null) {
ArrayList<String> authList = memberRolesMapper.getMemberRoles(memberVO.getMemberId());
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : authList) {
System.out.println(role);
authorities.add(new GrantedAuthorityImpl(role.toString()));
}
if (memberVO.getEnabled()) {
User user = new User(memberVO.getUserName(), memberVO.getPassword(), true, true, true, true, authorities);
return user;
} else {
logger.error("User with login: " + userName + " not Enabled in database. Authentication failed for user ");
throw new UsernameNotFoundException("User Not Enabled");
}
} else {
logger.error("User with login: " + userName + " not found in database. Authentication failed for user ");
throw new UsernameNotFoundException("user not found in database");
}
} else {
logger.error("No User specified in the login ");
throw new UsernameNotFoundException("No username specified");
}
}
}
注意这里的2件事。
org.springframework.security.core.userdetails.User
对象下,然后由该方法返回以弹出安全性。答案 1 :(得分:0)
您可以实施自己的自定义AuthenticationManager和自定义UsernamePasswordAuthenticationFilter。这是一个简单的例子,但它也可以为您提供一个信息,这也是安全上下文非常敏感的一部分:)
只需在spring_security.xml中创建bean:
<http entry-point-ref="authenticationProcessingFilterEntryPoint"
use-expressions="true">
<custom-filter ref="sessionManagementFilter" before="SESSION_MANAGEMENT_FILTER" />
<custom-filter ref="customUsernamePasswordAuthenticationFilter"
position="FORM_LOGIN_FILTER" />
<session-management
session-authentication-strategy-ref="sas"></session-management>
</http>
<beans:bean id="authenticationProcessingFilterEntryPoint"
class="org.springframework.security.web.authentication.AuthenticationProcessingFilterEntryPoint">
<beans:property name="loginFormUrl" value="/login" />
</beans:bean>
<beans:bean id="sas"
class="org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy" />
<beans:bean id="customAuthenticationManager"
class="my.package.security.CustomAuthenticationManager" />
<beans:bean id="customUsernamePasswordAuthenticationFilter"
class="my.package.security.CustomUsernamePasswordAuthenticationFilter">
<beans:property name="sessionAuthenticationStrategy"
ref="sas" />
<beans:property name="authenticationManager" ref="customAuthenticationManager" />
<beans:property name="authenticationSuccessHandler">
<beans:bean
class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
<beans:property name="defaultTargetUrl" value="/main.xhtml" />
</beans:bean>
</beans:property>
<beans:property name="authenticationFailureHandler">
<beans:bean
class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
<beans:property name="defaultFailureUrl" value="/login.xhtml" />
</beans:bean>
</beans:property>
</beans:bean>
<beans:bean id="sessionManagementFilter"
class="org.springframework.security.web.session.SessionManagementFilter">
<beans:constructor-arg name="securityContextRepository"
ref="httpSessionSecurityContextRepository" />
</beans:bean>
<beans:bean id="httpSessionSecurityContextRepository"
class="org.springframework.security.web.context.HttpSessionSecurityContextRepository" />
实施CustomUsernamePasswordAuthenticationFilter覆盖身份验证并添加外部逻辑时:
public final class CustomUsernamePasswordAuthenticationFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response){
CustomAuthentication auth = new CustomAuthentication();
// set details of current user
auth.setDetails(new WebAuthenticationDetails(request));
auth.setAuthenticated(true);
auth.setUserName(username);
// set authentication to current security session
LOGGER.info("Setting authentication into existing security context");
SecurityContextHolder.getContext().setAuthentication(auth);
// if validation done return generated authentication
return auth;
}
}
然后生成的身份验证对象将由身份验证管理器处理:
public final class CustomAuthenticationManager implements AuthenticationManager {
/*
* (non-Javadoc)
*
* @see org.springframework.security.authentication.AuthenticationManager#
* authenticate(org.springframework.security.core.Authentication)
*/
private static final Logger LOGGER = LoggerFactory.getLogger(CustomUsernamePasswordAuthenticationFilter.class);
private final BadCredentialsException badCredentialsException = new BadCredentialsException("Invalid username/password");
@Override
public Authentication authenticate(Authentication authentication) {
//check if user has valid authentication
if (authentication == null) {
LOGGER.debug("Null authentication");
throw badCredentialsException;
}
//Check mandatory fields
if (!Validator.isValidString((String) authentication.getPrincipal()) || !Validator.isValidString((String) authentication.getCredentials())) {
LOGGER.debug("Null/blank username/credential");
throw badCredentialsException;
}
//Check if there is any role assigned into user
if (authentication.getAuthorities() != null && authentication.getAuthorities().size() < 1) {
LOGGER.debug("No authority found");
throw badCredentialsException;
}
//Validate role
//IF ROLE VALIDATION REQUIRED YOU CAN HANDLE IT HERE
boolean authorityValid = false;
LOGGER.info("Validating user authentication. Total grantedAuth size: " + authentication.getAuthorities().size());
for (GrantedAuthority g : authentication.getAuthorities()) {
if (!authorityValid) {
//Testing purpose one type role available, when exact roles prepared create enum types
authorityValid = g.getAuthority().equals("ROLE_LDAP_AUTHENTICATED");
}
}
//if none of role matching to required throw exception
if(!authorityValid){
LOGGER.debug("User has authority but none of them matching");
throw badCredentialsException;
}
LOGGER.info("Final validation done returning authentication");
return authentication;
}
}
然后,如果需要,您也可以覆盖默认身份验证对象,如果动态位于此处的角色是您处理的位置:
public final class CustomAuthentication implements Authentication {
/**
*
*/
private static final long serialVersionUID = 1L;
private transient String userName;
private transient boolean authenticated;
private transient Object details;
private static final transient String ROLE = "ROLE_LDAP_AUTHENTICATED";
/*
* (non-Javadoc)
*
* @see java.security.Principal#getName()
*/
@Override
public String getName() {
return this.userName; //for dynamic username logic here
}
//IF ROLES DYNAMICALLY ALLOCATED ASSIGN IT HERE, HERE IS WHERE YOU READ FROM INTERCEPT URL
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.Authentication#getAuthorities()
*/
@Override
public Collection<GrantedAuthority> getAuthorities() {
Collection<GrantedAuthority> auths = new ArrayList<GrantedAuthority>();
auths.add(new GrantedAuthority() {
/**
*
*/
private static final long serialVersionUID = 1L;
@Override
public String getAuthority() {
if (authenticated) {
return ROLE;
}
return null;
}
});
return auths;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.Authentication#getCredentials()
*/
@Override
public Object getCredentials() {
//TODO: a specific algorithm can be stored
return userName + " is ldap authenticated user";
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.Authentication#getDetails()
*/
@Override
public Object getDetails() {
return this.details;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.Authentication#getPrincipal()
*/
@Override
public Object getPrincipal() {
return userName;
}
/*
* (non-Javadoc)
*
* @see org.springframework.security.core.Authentication#isAuthenticated()
*/
@Override
public boolean isAuthenticated() {
return this.authenticated;
}
/*
* (non-Javadoc)
*
* @see
* org.springframework.security.core.Authentication#setAuthenticated(boolean
* )
*/
@Override
public void setAuthenticated(boolean arg0) {
this.authenticated = arg0;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public void setDetails(Object details) {
this.details = details;
}
}
答案 2 :(得分:0)
实现保存用户信息的服务。
@Service
public class UserAuthenticationInfoService {
private final Map<String, UserInfo> infos = new HashMap<String, UserInfo>();
public void addUserInfo(UserInfo userInfo){
infos.put(userInfo.getUsername(), userInfo);
}
public UserInfo getUserInfo(String username) {
return infos.get(username);
}
}
您的控制器使用您从外部应用程序收到的用户信息填充UserAuthenticationInfoService服务。
然后实现自定义UserDetailsService来访问这些信息。
public class CustomerUserDetailsService implements UserDetailsService {
@Autowired
private UserAuthenticationInfoService service;
public UserDetails loadUserByUsername(String userName) throws UsernameNotFoundException, DataAccessException {
UserInfo info = service.getUserInfo(userName);
return new User(info.getUsername(), info.getPassword(), info.getAuthorities());
}
}
并设置spring安全上下文以使用此UserDetailsService(您可以在spring安全文档中找到它)