spring boot security 实战

最近需要新做一个项目,后端是spring boot ,由于涉及到用户权限验证,于是去看了看spring security,在这里记录一下配置过程

首先引入依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

我这里应该是比较新的版本,貌似我查了下是5以上的,顺便贴出spring boot版本

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.0.3.RELEASE</version>
</parent>

这时候启动项目,访问任意路径,你会发现页面转到/login页面


这是security内置的一个页面,如果不做任何配置时,未登录的请求将会被拦截到该页面,这里就不多做解释,接下来增加一些security的配置

创建类SpringSecurityConfig

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)//开启角色验证
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.formLogin()
                .loginPage("/login")           // 设置登录页面,未登录的用户将会被拦截到该页面
                .failureForwardUrl("/fail")     //验证失败时访问
                .defaultSuccessUrl("/index").permitAll().and() // 验证成功时访问

                .authorizeRequests()        // 定义哪些URL需要被保护、哪些不需要被保护
                .antMatchers("/login",// 设置所有人都可以访问登录页面,也可以不设置,反正被拦截了都是到这
                        "/amchart/**",
                        "/bootstrap/**",
                        "/bootstrap-table/**",
                        "/css/**",
                        "/documentation/**",
                        "/jquery-validation/**",
                        "/fonts/**",
                        "/layer/**",
                        "/js/**",
                        "/pages/**",
                        "/plugins/**").permitAll()     // 开放常用静态资源权限,这里的根路径为resources下的static
                .anyRequest()               // 任何请求,登录后可以访问
                .authenticated()
                .and()
                .logout().permitAll();
        http.csrf().disable();          // 关闭csrf防护
        http.logout().logoutSuccessUrl("/login"); // 注销时访问
    }

}

创建类MyUserDetailsService

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;

@Component
public class MyUserDetailsService implements UserDetailsService {

    private Logger logger = LoggerFactory.getLogger(getClass());


    @Autowired
    private PasswordEncoder passwordEncoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        logger.info("用户的用户名: {}", username);
        // TODO 根据用户名,查找到对应的密码,与权限

        String password = passwordEncoder.encode("123456");
        logger.info("password: {}", password);

        // 参数分别是:用户名,密码,用户权限
        User user = new User(username, password, AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
        /**
         * 正常项目这里的user应该是从数据库获取
         * User user = userService.findByUserName(username);
         */
        if (user != null) {
            List<GrantedAuthority> grantedAuthorities = new ArrayList<>();      //权限列表
            GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_ADMIN");//新建ADMIN角色的权限
            grantedAuthorities.add(grantedAuthority);
            return new User(user.getUsername(), user.getPassword(), grantedAuthorities);//生成系统用户
        } else {
            throw new UsernameNotFoundException("admin: " + username + " do not exist!");
        }
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        //密码需要加密,这里使用的内建
        return new BCryptPasswordEncoder();
    }
}

创建类MainController

import com.alibaba.fastjson.JSONObject;
import com.demo.bean.ResponseBean;
import com.demo.bean.User;
import com.demo.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.SessionAttribute;

import javax.servlet.http.HttpSession;


@Controller
@RequestMapping("/")
public class MainController {


    //登录url,这里一定要用GET,因为我没有重新配置security的登录请求url,默认登录请求是POST的/login
    //因为我使用了thymeleaf模板,这里返回login即返回到resources/templates/login.html
    //如未使用模板(现在很多需要使用模板),需配置spring.mvc.view.prefix与spring.mvc.view.suffix
    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String login() {
        return "/login";
    }

    /**
     * 考虑到现在很多登录页面页面为异步请求,于是返回了一个json表示请求结果
     * 如需挑战则去掉ResponseBody注解,返回页面地址即可
     * @param model
     * @return
     */
    @RequestMapping("/index")
    @ResponseBody
    @PreAuthorize("hasRole('ADMIN')")//匹配ADMIN角色(按照规则,录入权限时,需有一个前缀“ROLE_”,即“ROLE_ADMIN”),非ADMIN角色将被拒绝访问
    public String index(Model model) {
        JSONObject re = new JSONObject();
        re.put("status", true);
        return re.toJSONString();
    }

    @RequestMapping("/fail")
    @ResponseBody
    public String fail(Model model) {
        JSONObject re = new JSONObject();
        re.put("status", false);
        return re.toJSONString();
    }


}

重启项目即可(此处我没有写前端,测试可以随便写一个login页面)

此处的defaultSuccessUrl只对非拦截登录的用户生效

如果你是输入localhost:8080/page/books,然后被拦截到localhost:8080/login,那么当你登录成功时将自动重定向到localhost:8080/page/books

如果需要每次登录成功都到固定页面或返回固定结果,需要将defaultSuccessUrl改为successForwardUrl

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值