springboot-30-security(三)使用注解實現權限控制


上個博客: http://www.cnblogs.com/wenbronk/p/7381252.html中, 實現了經典5表對用戶進行權限的控制, 但太過於繁瑣了, 官方推薦的方式是將用戶和角色存儲數據庫, 權限直接在要訪問的接口上進行控制

(我感覺更麻煩...每個接口都需要指定)

本篇基於第一個, security: http://www.cnblogs.com/wenbronk/p/7379865.html

一, 數據庫: (更多可見 security(1) )

1, 數據表: 

SET FOREIGN_KEY_CHECKS=0;

-- ----------------------------
-- Table structure for `sys_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user` (
  `id` INT (64) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `username` varchar(32) DEFAULT NULL COMMENT '用戶名',
  `password` varchar(64) DEFAULT NULL COMMENT '密碼',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `sys_role`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role`;
CREATE TABLE `sys_role` (
  `id` INT (64) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `name` varchar(32) DEFAULT NULL COMMENT '用戶名',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;

-- ----------------------------
-- Table structure for `sys_role_user`
-- ----------------------------
DROP TABLE IF EXISTS `sys_role_user`;
CREATE TABLE `sys_role_user` (
  `id` int(64) NOT NULL AUTO_INCREMENT COMMENT '主鍵id',
  `sys_user_id` INT(64) NOT NULL COMMENT 'user_id',
  `sys_role_id` INT(64) NOT NULL COMMENT 'role_id',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=28 DEFAULT CHARSET=utf8;

ALTER TABLE sys_role_user ADD CONSTRAINT sys_FK1 FOREIGN KEY(sys_user_id) REFERENCES sys_user(id);
ALTER TABLE sys_role_user ADD CONSTRAINT role_FK2 FOREIGN KEY(sys_role_id) REFERENCES sys_role(id);
View Code

2, 插入數據

insert into SYS_USER (id,username, password) values (1,'vini', '$2a$10$n7sdY5rR1X3XOfZR6o2R.OdW0vvz3uidz0UEzVKV0CEyu0hGwIch.');
insert into SYS_USER (id,username, password) values (2,'bronk', '$2a$10$n7sdY5rR1X3XOfZR6o2R.OdW0vvz3uidz0UEzVKV0CEyu0hGwIch.');

insert into SYS_ROLE(id,name) values(1,'ROLE_ADMIN');
insert into SYS_ROLE(id,name) values(2,'ROLE_USER');

insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(1,1);
insert into SYS_ROLE_USER(SYS_USER_ID,sys_role_id) values(2,2);
View Code

這兒使用了 Bcrpy強hash加密, 我設置的密碼為 123, 

更多可見: http://blog.csdn.net/u012373815/article/details/60465776

3, 映射實體

SysUser.groovy

package com.wenbronk.security.entity

import com.fasterxml.jackson.annotation.JsonIgnore
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.userdetails.UserDetails

/**
 * Created by wenbronk on 2017/8/14.
 */
class SysUser implements UserDetails {
    int id
    String username
    @JsonIgnore
    String password
    String rawPass
    @JsonIgnore
    List<SysRole> roles
    List<? extends GrantedAuthority> authorities

    @Override
    @JsonIgnore
    Collection<? extends GrantedAuthority> getAuthorities() {
        return authorities
    }

    @Override
    @JsonIgnore
    boolean isAccountNonExpired() {
        return true
    }

    @Override
    @JsonIgnore
    boolean isAccountNonLocked() {
        return true
    }

    @Override
    @JsonIgnore
    boolean isCredentialsNonExpired() {
        return true
    }

    @Override
    @JsonIgnore
    boolean isEnabled() {
        return true
    }

    @Override
    public String toString() {
        return "SysUser{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                ", rawPass='" + rawPass + '\'' +
                ", roles=" + roles +
                ", authorities=" + authorities +
                '}';
    }
}

SysRole.groovy

package com.wenbronk.security.entity
/**
 * Created by wenbronk on 2017/8/14.
 */
class SysRole {
    int id
    String name

    @Override
    public String toString() {
        return "SysRole{" +
                "id=" + id +
                ", name=" + name +
                '}';
    }
}

4, mapper

SysUserMapper.groovy

package com.wenbronk.security.mapper

import com.wenbronk.security.entity.SysUser

/**
 * Created by wenbronk on 2017/8/14.
 */
interface SysUserMapper {
    SysUser findByUserName(String username)
}

SysUserMapper.xml

<?xml version="1.0" encoding="UTF-8" ?>
        <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.wenbronk.security.mapper.SysUserMapper">

<resultMap id="sys_user_map" type="SysUser">
    <id property="id" column="id" />
    <result property="username" column="username" />
    <result property="password" column="password" />
    <collection property="roles" ofType="SysRole">
        <result column="name" property="name" />
    </collection>

</resultMap>

<select id="findByUserName" parameterType="string" resultMap="sys_user_map">
    select u.id, u.username, u.password, r.name
    from sys_user u
    LEFT JOIN sys_role_user s on u.id = s.sys_user_id
    LEFT JOIN sys_role r on r.id = s.sys_role_id
    WHERE username = #{username}
</select>
</mapper>

二, security

1, WebSecurityConfig.groovy

package com.wenbronk.security.security.config

import com.wenbronk.security.security.interceptor.MyFilterSecurityInterceptor
import com.wenbronk.security.security.service.CustomUserService
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
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 javax.inject.Inject
/**
 * Created by wenbronk on 2017/8/15.
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true) // 控制權限注解
class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Inject
    CustomUserService customUserService;
    @Autowired
    MyFilterSecurityInterceptor myFilterSecurityInterceptor

    /**
     * 設置加密方式為 BCrypt強hash
     */
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(customUserService).passwordEncoder(new BCryptPasswordEncoder());
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // 關閉 csrf()
        http.csrf().disable()
                .authorizeRequests()
                .antMatchers("/users**").authenticated()
                .antMatchers(HttpMethod.POST).authenticated()
                .antMatchers(HttpMethod.PUT).authenticated()
                .antMatchers(HttpMethod.DELETE).authenticated()
                .antMatchers("/**")
                .permitAll()
                .and()
                .sessionManagement()
                // 使用basic認證登陸
                .and().httpBasic()
    }
}

這兒需要關閉 csrf 和使用 basic 認證, 相信可見: 

http://blog.csdn.net/u012373815/article/details/55047285
http://blog.csdn.net/u012373815/article/details/56832167

CustomerUserService.groovy

package com.wenbronk.security.security.service

import com.wenbronk.security.entity.SysUser
import com.wenbronk.security.mapper.SysUserMapper
import org.springframework.security.core.GrantedAuthority
import org.springframework.security.core.authority.SimpleGrantedAuthority
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 javax.inject.Inject
/**
 * Created by wenbronk on 2017/8/15.
 */
@Service
class CustomUserService implements UserDetailsService {

    @Inject
    SysUserMapper sysUserMapper
//    @Inject
//    SysPermissionMapper sysPermissionMapper

    @Override
    UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {
        def sysUser = sysUserMapper.findByUserName(s) as SysUser
        assert sysUser != null

        List<GrantedAuthority> authorities = new ArrayList<>()
        sysUser.getRoles().each { role ->
            // 將用戶的權限添加到 authrities中就可以了
            authorities.add(new SimpleGrantedAuthority(role.getName()))
        }
        sysUser.setAuthorities(authorities)
        return sysUser

    }
}

三, 接口控制: 

登陸使用的

    @RequestMapping(value = "/login")
    public Object login(@AuthenticationPrincipal SysUser loginUser, @RequestParam(name = "logout", required = false) String logout) {
        if (logout != null) {
            return null
        }
        if (loginUser != null) {
            return loginUser
        }
        return null
    }

權限接口控制: 

package com.wenbronk.security.controller

import com.wenbronk.security.entity.SysUser
import org.springframework.security.access.annotation.Secured
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod
import org.springframework.web.bind.annotation.RestController
/**
 * Created by wenbronk on 2017/8/17.
 */
@RestController
@RequestMapping("/users")
class HomeController {

    /**
     * 所有可訪問
     */
    @RequestMapping(method = RequestMethod.GET)
    String getusers() {
        'getUsers'
    }

    @Secured(value = ['ROLE_ADMIN', 'ROLE_USER'])
    @RequestMapping(method = RequestMethod.POST)
    String save(@RequestBody SysUser user) {
        user.toString()
    }

    /**
     * 只有admin可訪問
     */
    @Secured(value = ['ROLE_ADMIN'])
    @RequestMapping(method = RequestMethod.PUT)
    String update() {
        'updateUser'
    }

    @Secured(value = ['ROLE_ADMIN'])
    @RequestMapping(method = RequestMethod.DELETE)
    String delete() {
        'deleteUser'
    }

}

四, 訪問: 

1, get訪問

 

 2, post訪問, 請求體為: 

{
    "id": 1,
    "username": "vini",
    "password": "123",
    "rawPass": "123"
}

 

 

 3, put請求, 此處使用的用戶沒有權限

 

 4, delete請求, 換有權限的用戶

 這樣, 就可以實現具體方法的訪問權限控制, 包括rest請求

 

 ps: basic64登陸, 需要密碼, 可以使用工具生成, 也可以抓包

 

 原博客地址: 

http://blog.csdn.net/u012373815/article/details/59749385

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM