• Stars
    star
    334
  • Rank 126,264 (Top 3 %)
  • Language
    Java
  • Created about 9 years ago
  • Updated over 8 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

基于 Spring MVC,提供 API 服务端的身份验证功能。通过 Redis、MySQL 维护登录用户与分配 Token 的映射关系。

Spring Authorization Manager

为Api服务端添加简单的Token鉴权功能,基于Spring MVC

功能简述

  1. 对每个请求进行身份验证,如果身份验证失败直接返回错误信息(可以自定义错误信息和Http状态码)
  2. 通过鉴权信息获得当前登录的用户,并自动注入到Controller的方法中

使用方法

仓库:

<repository>
    <id>scienjus-mvn-repo</id>
    <url>https://raw.github.com/ScienJus/maven/snapshot/</url>
    <snapshots>
        <enabled>true</enabled>
        <updatePolicy>always</updatePolicy>
    </snapshots>
</repository>

依赖:

<dependency>
    <groupId>com.scienjus</groupId>
    <artifactId>spring-authorization-manager</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>

所有依赖库,相信大部分已经存在于你的项目中了:

<dependencies>
  <dependency>
	  <groupId>com.scienjus</groupId>
	  <artifactId>spring-authorization-manager</artifactId>
	  <version>1.0-SNAPSHOT</version>
  </dependency>
  <!--Spring MVC依赖-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
  </dependency>
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-core</artifactId>
  </dependency>
  <dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
  </dependency>
  <dependency>
    <groupId>javax.servlet</groupId>
    <artifactId>javax.servlet-api</artifactId>
  </dependency>
  <!--Redis依赖,只有在使用RedisTokenManager时才需要-->
  <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
  </dependency>
  <!--数据库依赖,只有在使用MySQLTokenManager时才需要-->
  <dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
  </dependency>
  <dependency>
    <groupId>commons-dbcp</groupId>
    <artifactId>commons-dbcp</artifactId>
  </dependency>
</dependencies>

使用Redis存储Token

将Jedis客户端注入到RedisTokenManager

<!--Redis配置-->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
</bean>

<!--Redis连接池-->
<bean id = "jedisPool" class="redis.clients.jedis.JedisPool">
  <constructor-arg index="0" ref="jedisPoolConfig"/>
  <constructor-arg index="1" value="${redis.host}"/>
  <constructor-arg index="2" value="${redis.port}" type="int"/>
  <constructor-arg index="3" value="${redis.timeout}" type="int"/>
  <constructor-arg index="4" value="${redis.password}"/>
</bean>

<!--管理验证信息的bean-->
<bean id="tokenManager" class="com.scienjus.authorization.manager.impl.RedisTokenManager">
       <!--Token失效时间-->
       <property name="tokenExpireSeconds" value="3600" />
       <!--Redis客户端-->
       <property name="jedisPool" ref="jedisPool" />
</bean>

使用MySQL存储Token

只需要将RedisTokenManager替换成MySQLTokenManager,并将数据源注入进去:

<!--数据源-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
       <property name="url" value="jdbc:mysql://127.0.0.1:3306/demo"/>
       <property name="username" value="root"/>
       <property name="password" value="root"/>
</bean>

<!--管理验证信息的bean-->
<bean id="tokenManager" class="com.scienjus.authorization.manager.impl.DBTokenManager">
       <!--Token失效时间-->
       <property name="tokenExpireSeconds" value="3600" />
       <!--数据源-->
       <property name="dataSource" ref="dataSource" />
       <!--存储验证信息的表名-->
       <property name="tableName" value="users" />
       <!--存储Key的字段名-->
       <property name="keyColumnName" value="username" />
       <!--存储Token的字段名-->
       <property name="tokenColumnName" value="token" />
       <!--存储Token过期时间的字段名-->
       <property name="expireAtColumnName" value="expire_at" />
</bean>

配置身份验证的拦截器

将配置好的TokenManager注入到AuthorizationInterceptor中:

<mvc:interceptors>
       <!--身份验证的拦截器-->
       <bean id="authorizationInterceptor" class="com.scienjus.authorization.interceptor.AuthorizationInterceptor">
              <!--验证信息存储的Http头-->
              <property name="httpHeaderName" value="authorization" />
              <!--验证信息通用前缀,例如Bearer-->
              <property name="httpHeaderPrefix" value="" />
              <!--验证失败时的错误信息-->
              <property name="unauthorizedErrorMessage" value="令牌失效,请重新登录" />
              <!--管理验证信息的bean-->
              <property name="manager" ref="tokenManager" />
       </bean>
</mvc:interceptors>

接下来只需要对需要身份验证的方法加上@Authorization注解即可,例如:

@RestController
@RequestMapping("/home")
public class TokenController {

    @RequestMapping(method = RequestMethod.GET)
    @Authorization
    public ResponseEntity<String> home() {
        return new ResponseEntity<>("Hello World", HttpStatus.OK);
    }

}

也可以直接在Controller类上加上该注解,这将会使该Controller中的所有方法都需要进行身份验证。

配置获得当前登录用户的解析器

首先需要实现UserModelRepository接口的getCurrentUser方法,可以通过Key得到对应的用户对象,然后配置一个解析器,并将其注入到CurrentUserMethodArgumentResolver

<mvc:annotation-driven>
       <mvc:argument-resolvers>
              <!--配置注入登录用户的解析器-->
              <bean id="currentUserMethodArgumentResolver" class="com.scienjus.authorization.resolvers.CurrentUserMethodArgumentResolver">
                     <!--需要解析的用户类-->
                     <property name="userModelClass" value="com.scienjus.domain.User" />
                     <!--查询用户的bean-->
                     <property name="userModelRepository" ref="userRepository" />
              </bean>
       </mvc:argument-resolvers>
</mvc:annotation-driven>

<!--通过Key获得对应用户的bean-->
<bean id="userRepository" class="com.scienjus.repository.UserRepository" />

然后只需要在方法的参数上添加一个用户对象,并加上@CurrentUser注解,例如:

@RestController
@RequestMapping("/home")
public class TokenController {

    @RequestMapping(method = RequestMethod.GET)
    @Authorization
    public ResponseEntity<String> home(@CurrentUser user) {
        return new ResponseEntity<>("Hello " + user.getUsername(), HttpStatus.OK);
    }

}

需要注意的是,拥有@CurrentUser参数的方法,可以没有@Authorization注解,此时如果请求未登录,该参数会为null

但是如果想要使用CurrentUserMethodArgumentResolver则必须配置AuthorizationInterceptor

###更新日志

2016-3-1

增加了泛型约束

2015-11-27

修改了拦截器的部分代码,内容为:

  1. 将返回鉴权失败信息的输出流从response.getWriter改为了response.getOutputStream,因为@ResponseBody默认也是用的后者,便于统一监控返回内容。
  2. 可以通过配置文件自定义鉴权失败的http状态码了,默认为401(unauthorized)。
  3. 将返回鉴权失败的Content-Type设置为application/json了,否则可能会导致iOS的网络库AFNetWorking解析报错。

###帮助

如果您在使用中遇到了问题,可以给我提 Issues,或是通过邮件联系我,我的邮箱是:[email protected]

源码分析见我的这篇博客

一个简单的Demo

More Repositories

1

smartqq

SmartQQ(WebQQ)的Api ,你可以用它实现自己的QQ 机器人 a qq robot based on smartqq (webqq) api
Java
1,149
star
2

spring-restful-authorization

这个 Demo 用于演示如何在 RESTful 下使用自定义 Token 保持客户端登录状态,依靠 Spring 的拦截器和解析器完成权限验证及登录用户注入,并使用 Redis 存储 Token。
Java
859
star
3

qqbot

基于SmartQQ(WebQQ)的QQ机器人 / a qq robot based on smartqq(webqq) api
Ruby
280
star
4

spring-redis-mq

基于 Spring 和 Redis 的分布式消息队列(MessageQueue)实现
Java
118
star
5

pixiv-crawler

通过网页爬虫批量下载 Pixiv 图片
Java
57
star
6

pixiv-parser

批量抓取和下载 Pixiv 上的图片 Batch download pictures from Pixiv
Java
36
star
7

spring-authorization-manager-demo

https://github.com/ScienJus/spring-authorization-manager 的Demo
Java
34
star
8

spring-disque

基于 Spring 和 Jedis 的 Disque 封装,使用注解驱动
Java
22
star
9

spring-cloud-etcd

[WIP] Etcd integration with Spring Cloud, based on etcd v3 api(jetcd).
Java
20
star
10

elasticsearch-chinese-analyzers-contrasts

Elasticsearch中文分词插件分词效果对比(Ik、Ansj、Mmseg和Jieba)
JavaScript
10
star
11

play-with-ruby

记录个人学习 Ruby 的过程
Ruby
10
star
12

smzdm-push

什么值得买非官方的邮件推送,http://smzdm.scienjus.com/ 简单测试中(注册密码必须8位以上)
Ruby
6
star
13

fastroute-spring

nikic/FastRoute implementation in Spring
Java
6
star
14

django_gaode_maps

Django 管理后台的高德地图控件
Python
5
star
15

thrift-spring-boot-starter

[WIP] Apache Thrift integration with Spring Boot. nonblocking client/server, service discovery, load balancing and more.
Java
4
star
16

mybatis-redis-counter

use redis to counting in mybatis, non invasive and easy to use / 在MyBatis项目中使用Redis辅助计数,使用简单且无侵入性
Java
3
star
17

konata

micro web framework like Pippo and written in Kotlin
Kotlin
3
star
18

sofa-rpc-consul-registry-demo

Java
2
star
19

learn-spring-restdocs

Learn how to use Spring REST Docs based on Spring Boot2 and JUnit5.
HTML
1
star
20

fckjnb

工行猴年纪念币预约脚本
Ruby
1
star
21

sofa-rpc-hystrix-with-spring-cloud-example

Java
1
star