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

 

posted @ 2017-08-17 17:28  bronk  阅读(9570)  评论(0编辑  收藏  举报