在SpringMVC+Spring工程中使用SpringSecurity4.2.3

原创
小哥 3年前 (2022-11-02) 阅读数 2 #大杂烩

Spring Security 为基于Java EE 企业软件应用提供全面的安全服务(官方)。使用 Spring Securituy 可以方便地为一个 Web 进行用户登录认证、权限控制。可以通过轮廓法和Java配置方式。以下是两种方法:

准备

1 Maven 坐标


    org.springframework.security
    spring-security-web
    4.2.3.RELEASE

 
    org.springframework.security 
    spring-security-config 
    4.2.3.RELEASE 


    org.springframework.security
    spring-security-taglibs
    4.2.3.RELEASE

2 在 web.xml 中配置 Spring Security 过滤器


    springSecurityFilterChain
    org.springframework.web.filter.DelegatingFilterProxy


    springSecurityFilterChain
    /*

方式一 轮廓法

1 添加配置文件 spring-security.xml,并在 web.xml 在以下位置扫描此配置文件




    

    
    

    
    
    

    
        
        

        

        
        

        
        

        
        

        
            
            
        

        
    

    
    
    
    

    
    
        
        
        
            
        
    

    
         
    

    

2 配置文件中使用的自定义类。

2.1 UserDetailsServiceImpl

import java.util.List;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import diary.mapper.UserMapper;
import diary.pojo.User;

/**
 * 根据用户提交的用户名查询用户信息。
 */
public class UserDetailsServiceImpl implements UserDetailsService {
    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        if(StringUtils.isEmpty(username)) {
            throw new BadCredentialsException("用户名不能为空");
        }

        UserDetails userDetails = null;
        // 根据用户名从数据库中查询用户信息,按照自己的业务规则编写。
        User user = this.userMapper.getUserByUsername(username);
        if(user == null) {
            throw new BadCredentialsException("用户名不存在");
        }
        userDetails = new org.springframework.security.core.userdetails.User(
                user.getUsername(), 
                user.getPassword(), // 存储在数据库中的密码    
                true,               // 用户是否处于激活状态
                true,               // 帐户是否已过期
                true,               // 证书是否已过期
                true,               // 账号是否被锁定
                AuthorityUtils.createAuthorityList("ROLE_" + user.getType()));  // 用户角色列表,必须为 ROLE_ 开头
        return userDetails;
    }
}

2.2 MyMessageDigestPasswordEncoder

import org.apache.commons.lang3.StringUtils;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder;

import diary.common.util.MD5Util;

/**
 * 用于自定义用户提交的密码。
 */
public class MyMessageDigestPasswordEncoder extends MessageDigestPasswordEncoder {

    public MyMessageDigestPasswordEncoder(String algorithm) {
        super(algorithm);
    }

    /**
     * encPass:用户的密码真的是
     * raw:用户提交的密码
     * 
     */
    @Override
    public boolean isPasswordValid(String encPass, String rawPass, Object salt) {
        if(StringUtils.isEmpty(rawPass)) {
            throw new BadCredentialsException("密码不能为空");
        }
        return encPass.equals(MD5Util.md5(rawPass));
    }

}

2.3 AuthenticationSuccessHandlerImpl

import java.io.IOException;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import diary.mapper.UserMapper;
import diary.pojo.User;

/**
 * 对于成功登录身份验证后执行的操作
 */
public class AuthenticationSuccessHandlerImpl implements AuthenticationSuccessHandler {
    @Resource
    private UserMapper userMapper;

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
            Authentication authentication) throws IOException, ServletException {
        // UserDetails 用户名等信息存储在
        UserDetails userDetails = (UserDetails) authentication.getPrincipal();
        // 获取用户信息,并根据您自己的业务规则进行编写。
        User user = this.userMapper.getUserByUsername(username);
        // 将用户放入 Session
        request.getSession().setAttribute("currUser", user);
        // 跳转到主页
        response.sendRedirect(request.getContextPath() + "/home.html");
    }

}

2.4 AuthenticationFailureHandlerImpl

import java.io.IOException;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;

/**
 * 用于在用户登录身份验证失败后执行的操作
 */
public class AuthenticationFailureHandlerImpl implements AuthenticationFailureHandler {

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException exception) throws IOException, ServletException {
        // AuthenticationException 存储异常信息,将其取出并放入 Request 转发到登录页。
        request.setAttribute("error", exception.getMessage());
        request.getRequestDispatcher("/login").forward(request, response);
    }

}

方式二 注解+Java 一种代码配置方法

这个类等同于上面的 spring-security.xml,其中各种配置可以对应于 spring-security.xml 中的配置项。四个定制类保持不变。需要强调的是,时间必须到位。 Spring 在扫描配置文件中的此类。所在的包。

package diary.security.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.encoding.MessageDigestPasswordEncoder;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;

import diary.security.AuthenticationFailureHandlerImpl;
import diary.security.AuthenticationSuccessHandlerImpl;
import diary.security.MyMessageDigestPasswordEncoder;
import diary.security.UserDetailsServiceImpl;

/**
 * 批注方法配置 Spring Security,请注意需要在 Spring 扫描配置文件中的此类。
 */
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) throws Exception {
        // 设置无阻止规则
        web.ignoring().antMatchers("/login", "/error/**", "/css/**", "/help/**", "/img/**", "/js/**", "/res/**");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 自定义 accessDecisionManager 门禁控制器,并打开表情语言
        http.authorizeRequests()
                .expressionHandler(webSecurityExpressionHandler())          // 启用 SpEL 表达式
                .antMatchers("/user/**").hasRole("0")                       // 访问 /user/** 必须有角色 "0",当使用标签时 
                .and().exceptionHandling().accessDeniedPage("/error/403")   // 在指定的登录身份验证成功后,用户访问未经授权的 URL 将跳转的 URL
                .and().authorizeRequests().anyRequest().authenticated();    // 指定需要登录所有请求

        // 打开默认登录页面
        // http.formLogin();

        // 自定义登录页面
        http.formLogin().loginPage("/login")                        // 指定登录页面
            .loginProcessingUrl("/user/doLogin")                    // 执行登录操作 URL
            .usernameParameter("username")                          // 用户请求登录时提交的用户名参数
            .passwordParameter("password")                          // 用户请求登录时提交的密码参数
            .failureHandler(this.authenticationFailureHandler())    // 定义登录身份验证失败后应执行的操作
            .successHandler(this.authenticationSuccessHandler());   // 定义登录身份验证后执行的操作

        // 自定义注销
        http.logout().logoutUrl("/user/logout")                     // 执行注销操作。 URL
            .logoutSuccessUrl("/login")                             // 注销成功后跳转的页面
            .invalidateHttpSession(true)
            .deleteCookies("JSESSIONID");

        // session 管理
        http.sessionManagement().sessionFixation().none().maximumSessions(1);

        // 禁用 CSRF 
        http.csrf().disable();
    }

    /**
     * 登录身份验证配置
     */
    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(this.userDetailsService())          
            .passwordEncoder(this.messageDigestPasswordEncoder());  
    }

    /**
     * 使用需要继承的自定义登录密码加密规则。  MessageDigestPasswordEncoder
     */
    @Bean(name = "myMessageDigestPasswordEncoder")
    public MessageDigestPasswordEncoder messageDigestPasswordEncoder() {
        return new MyMessageDigestPasswordEncoder("md5");
    }

    /**
     * 使用自定义登录身份验证失败处理类,需要继承 AuthenticationFailureHandler
     */
    @Bean(name = "authenticationFailureHandlerImpl")
    public AuthenticationFailureHandler authenticationFailureHandler() {
        return new AuthenticationFailureHandlerImpl();
    }

    /**
     * 使用自定义登录身份验证成功处理类需要继承 AuthenticationSuccessHandler
     */
    @Bean(name = "authenticationSuccessHandlerImpl")
    public AuthenticationSuccessHandler authenticationSuccessHandler() {
        return new AuthenticationSuccessHandlerImpl();
    }

    @Bean(name = "userDetailsServiceImpl")
    public UserDetailsService userDetailsService() {
        return new UserDetailsServiceImpl();
    }

    // 表达式控制器
    @Bean(name = "expressionHandler")
    public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
        return new DefaultWebSecurityExpressionHandler();
    }

}

另附

您可以在前端页面上使用它。 Spring Security 提供的标签控制元素的显示。
可参考 http://blog.csdn.net/running_snail_/article/details/7167771
下面是一个简单的例子:

<%-- 只有一个角色“0“用户可以看到它标签 --%>

    
版权声明

所有资源都来源于爬虫采集,如有侵权请联系我们,我们将立即删除