Java 这个Spring安全示例究竟是如何工作的?

Java 这个Spring安全示例究竟是如何工作的?,java,spring,spring-mvc,jakarta-ee,spring-security,Java,Spring,Spring Mvc,Jakarta Ee,Spring Security,我对SpringSecurity是个新手,我对教程中的配置有些怀疑 这是用于将spring安全配置导入项目的spring security.xml文件: <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmln

我对SpringSecurity是个新手,我对教程中的配置有些怀疑

这是用于将spring安全配置导入项目的spring security.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:security="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-4.0.xsd
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <security:http>
        <security:intercept-url pattern="/springLogin" access="permitAll"/>
        <security:intercept-url pattern="/doSpringLogin" access="permitAll"/>
        <security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>
        <security:intercept-url pattern="/springHome" access="hasRole('ROLE_USER')"/> 
        <security:intercept-url pattern="/products" access="hasRole('ROLE_USER')"/> 
        <security:intercept-url pattern="/springLogout" access="permitAll"/>
        <security:intercept-url pattern="/springLogin?error=true" access="permitAll"/>
        <security:form-login login-page="/springLogin" login-processing-url="/doSpringLogin"
        default-target-url="/springHome" authentication-failure-url="/springLogin?error=true"
        username-parameter="username" password-parameter="password"
        />
        <security:csrf disabled="true"/>
        <security:logout logout-url="/springLogout" logout-success-url="/springLogin"/>
    </security:http>

    <bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>

    <bean id="authenticationProvider" class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
        <property name="userDetailsService" ref="userDetailsServiceImpl"></property>
    </bean>

    <bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
        <constructor-arg name="providers">
            <list>
                <ref bean="authenticationProvider"/>
            </list>
        </constructor-arg>
    </bean>

    <security:authentication-manager>
        <security:authentication-provider user-service-ref="userDetailsServiceImpl">
            <security:password-encoder hash="plaintext"></security:password-encoder>
        </security:authentication-provider>
    </security:authentication-manager>

</beans>

我把它分成几个部分。第一个是标记内容

它包含以下内容:

<security:intercept-url pattern="/springLogin" access="permitAll"/>

我认为这意味着与/springLogin资源相关的页面在

<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>

表示与/myprofile资源相关的资源仅可供设置了角色的登录用户(主体)访问

这个推理正确吗

然后在上一个配置文件中有:

1) authenticationManagerbean的声明:

<bean id="authenticationManager" class="org.springframework.security.authentication.ProviderManager">
    <constructor-arg name="providers">
        <list>
            <ref bean="authenticationProvider"/>
        </list>
    </constructor-arg>
</bean>

我认为Spring使用它来用主体对象(例如web应用程序的所有用户)和权限填充SecurityContext(具体的主体可以做什么)

这个推理正确吗

此对象将必须提供主体信息的自动验证提供者bean列表作为构造函数arg(例如,与特定主体关联的角色)

在本例中,提供了一个DaoAuthenticationProvider类的实现,该类将具有name=“userDetailsService”的bean作为属性,如下所示:

<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        System.out.println(username);
        User user = RegisteryDAO.getUserDAO().getUserByUsername(username);

        if(user == null){
            return null;
        }

        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority(user.getRole()));

        UserDetails userDetails = new org.springframework.security.core.userdetails.
                User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);


        return userDetails;
    }

}

这是UserDetailsServiceImpl类的一个实例,这个:

<bean id="userDetailsServiceImpl" class="com.demo.security.UserDetailsServiceImpl"></bean>
public class UserDetailsServiceImpl implements UserDetailsService {

    @Override
    public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException {
        System.out.println(username);
        User user = RegisteryDAO.getUserDAO().getUserByUsername(username);

        if(user == null){
            return null;
        }

        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
        authorities.add(new SimpleGrantedAuthority(user.getRole()));

        UserDetails userDetails = new org.springframework.security.core.userdetails.
                User(user.getUsername(), user.getPassword(), true, true, true, true, authorities);


        return userDetails;
    }

}
公共类UserDetailsServiceImpl实现UserDetailsService{
@凌驾
公共用户详细信息loadUserByUsername(字符串用户名)
抛出UsernameNotFoundException{
System.out.println(用户名);
User User=RegisteryDAO.getUserDAO().getUserByUsername(用户名);
if(user==null){
返回null;
}
列表权限=新建ArrayList();
添加(新的SimpleGrantedAuthority(user.getRole());
UserDetails UserDetails=new org.springframework.security.core.UserDetails。
用户(User.getUsername(),User.getPassword(),true,true,true,authorities);
返回用户详细信息;
}
}
那么到底发生了什么

使用调试器,在我看来,当te用户尝试访问特定页面时,此loadUserByUsername()返回与登录用户相关的UserDetails对象,其中包含表示与特定登录用户相关联的角色的列表(例如先前的角色\u用户

然后我认为弹簧会自动使用

<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')"/>

检查用户是否已将propper角色设置到上一个列表中


如果它将请求转发给处理此Http请求的控制器方法,否则请避免此HttpRequest到达此控制器方法,并显示一个页面,说明用户无法访问此资源。

以下是您所询问的一些概念和问题的解释


AuthenticationManager
AuthenticationManager
是负责处理
身份验证
请求的组件。身份验证请求可能是用户名/密码登录的实例

对于其他实现,请参阅

AuthenticationManager
还包含
AuthenticationProvider
实现的集合。这些组件能够处理特定的
Authentication
类型,并且
AuthenticationManager
对它们进行迭代,试图找到一个能够处理传递给它的
验证的组件。如果它找到了一个,它将调用它,并显示
Authentication
对象,如果成功,则返回完全填充的
Authentication
对象(否则将抛出
AuthenticationException


AuthenticationProvider
如上所述,
AuthenticationProvider
处理特定类型的
Authentication
请求。例如,
DaoAuthenticationProvider
在被
AuthenticationManager
调用时将执行以下步骤:

  • 获取传递给它的
    UsernamePasswordAuthenticationToken
  • 使用提供给它的
    UserDetailsService
    服务实现(在您的情况下是
    userdetailserviceinpl
    )按用户名查找用户
  • 使用
    PasswordEncoder
    SaltSource
    检查身份验证令牌中提供的密码(如果指定)
  • 如果身份验证成功,则返回填充的身份验证对象(
    UsernamePasswordAuthenticationToken
    ),该对象包含主体、凭据并标记为
  • 如果身份验证失败,将抛出
    AuthenticationException
DaoAuthenticationProvider
您正在使用的能够处理
UsernamePasswordAuthenticationToken
请求的身份验证提供程序。通常是表单登录等等。您可以通过查看其
支持()来查看身份验证提供程序支持哪些类型
方法实现,在
DaoAuthenticationProvider
的情况下如下所示:

public boolean supports(Class<?> authentication) {
    return (UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}

使用调试器似乎
<security:intercept-url pattern="/myprofile" access="hasRole('ROLE_USER')" />