springboot集成springsecurity简单权限管理与logout退出,@AuthenticationPrincipal

springsecurity主要是 认证 (密码登录) 与 授权 (角色权限管理)

下面一个简单项目例子,使用springsecurity的权限管理

  • MyUserDetailsService#loadUserByUsername 用户登录查询
  • SecurityConfig#configure 配置springsecurity行为
  • Controller中的@PreAuthorize就是判断用户角色权限

理解权限关系怎么在springsecurity中实现

  • 用户:abc(角色admin,userRole),ccc(角色userRole)
  • 角色:admin (权限Lsit,Add),userRole(权限List)
  • 资源(权限):List,Add

项目结构
spring security 项目

http://127.0.0.1:8080/index 首页,不用权限
http://127.0.0.1:8080/list 会跳转到login,输入ccc,456 登录 (springsecurity自动拦截login的post请求,进入MyUserDetailsService#loadUserByUsername),可以看http://127.0.0.1:8080/list,但是http://127.0.0.1:8080/add需要admin角色,会报错
http://127.0.0.1:8080/logout 跳转到index,虽然没有在controller写logout,但是springsecurity自动有了( 在SecurityConfig#configure配置的loguot端点)
http://127.0.0.1:8080/login 输入abc,123登录,可以看 /list与 /add
基本完成权限控制与角色权限控制

密码没有BCrypt加密(字符串开头$2a),会报错 Encoded password does not look like BCrypt

//App.java
package boottest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @author zhanghui
 * @date 2019/4/24
 */
@SpringBootApplication
public class App {
    public static void main(String[] args) {

        SpringApplication.run(App.class);

        System.out.printf("test here!");
    }
}
//SysUser.java
package boottest.auth;

/**
 * @author zhanghui
 * @date 2019/4/24
 */
public class SysUser {
    private String userName;
    private String password;
    private String roles;

    public SysUser(String userName, String password, String roles) {
        this.userName = userName;
        this.password = password;
        this.roles = roles;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRoles() {
        return roles;
    }

    public void setRoles(String roles) {
        this.roles = roles;
    }
}
//SecurityConfig.java
package boottest.auth;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
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;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * @author zhanghui
 * @date 2019/4/24
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)  //  启用方法级别的权限认证
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyUserDetailsService myUserDetailsService;


    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //  允许所有用户访问"/"和"/index.html"
        http.authorizeRequests()
                .antMatchers("/", "/index").permitAll()
                .anyRequest().authenticated()   // 其他地址的访问均需验证权限
                .and()
                .csrf().disable() //暂时关闭csrf,不知道java获取csrf放入form表单
                .formLogin() // form提交登录
                .loginPage("/login")   //  登录页
                .failureUrl("/login-error").permitAll()
                .and()
                .logout()  //   添加 /logout 访问点,能退出
                .logoutSuccessUrl("/index");  //退出后访问
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(myUserDetailsService).passwordEncoder(passwordEncoder());
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
}
//MyUserDetailsService.java
package boottest.auth;

import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.AuthorityUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
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.stereotype.Service;

import java.util.List;

/**
 * @author zhanghui
 * @date 2019/4/24
 */
@Service
public class MyUserDetailsService implements UserDetailsService {

    /**
     * 根据用户的角色判断权限
     */

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

        //模拟数据库
        SysUser sysUser;
        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
        if("abc".equals(username)){
            sysUser=new SysUser("abc",passwordEncoder.encode("123")),"ROLE_admin,ROLE_user");
        }else if("ccc".equals(username)){
            sysUser=new SysUser("ccc",passwordEncoder.encode("456")), "ROLE_user");
        }else {
            sysUser=null;
        }
        if (null == sysUser) {
            throw new UsernameNotFoundException(username);
        }
        // authorities 是 roles 集合
        List<GrantedAuthority> authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(sysUser.getRoles());

        //上面是根据用户名查出用户信息,下面才会比较传来的password是否正确
        return new User(sysUser.getUserName(), sysUser.getPassword(), authorities);
    }
}
//Controller.java
package boottest.auth;

import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

/**
 * @author zhanghui
 * @date 2019/4/24
 */
@RestController
@ResponseBody
public class Controller {

    @GetMapping(value = {"/",""})
    public String defaut(){
        return "defaut";
    }

    @GetMapping("/index")
    public String index(){
        return "index";
    }

    // direct request to "/logout" for logout
    @RequestMapping("/login")
    public String login(){
        return "<form action=\"/login\" method=\"post\">\n" +
                "    <label for=\"username\">Username</label>:\n" +
                "    <input type=\"text\" id=\"username\" name=\"username\" autofocus=\"autofocus\" /> <br />\n" +
                "    <label for=\"password\">Password</label>:\n" +
                "    <input type=\"password\" id=\"password\" name=\"password\" /> <br />\n" +
                "    <input type=\"submit\" value=\"Login\" />\n" +
                "</form>";
    }

    @GetMapping("/login-error")
    public String loginerror(){
        return "login-error";
    }

//    @PreAuthorize("hasAuthority('ROLE_user')")  //判断角色
    @PreAuthorize("hasRole('user')")       //同上,判断角色,会自动加 前缀 ROLE_
    @GetMapping("/list")
    public String list() {
        //程序内判断role, 或者@AuthenticationPrincipal注解取得MyUserDetailsService内的UserDetails
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        if(authentication.getAuthorities().contains(new SimpleGrantedAuthority("ROLE_user"))){
            System.out.println("user role2");
        }
        return "to list";
    }

    @PreAuthorize("hasAuthority('ROLE_admin')")
    @GetMapping("/add")
    public String add() {
        return "to add";
    }
}
  • 4
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值