中心服务器授权许可文件,spring cloud oauth2 搭建认证中心(授权服务器)

单点登录

什么是单点登录?单点登录全称Single Sign On(以下简称SSO),是指在多系统应用群中登录一个系统,便可在其他所有系统中得到授权而无需再次登录,包括单点登录与单点注销两部分

相比于单系统登录,sso需要一个独立的认证中心,只有认证中心能接受用户的用户名密码等安全信息,其他系统不提供登录入口,只接受认证中心的间接授权。间接授权通过令牌实现,sso认证中心验证用户的用户名密码没问题,创建授权令牌,在接下来的跳转过程中,授权令牌作为参数发送给各个子系统,子系统拿到令牌,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。这个过程,也就是单点登录的原理。

oauth2

在oauth中我们通常将他分为认证中心和资源中心。二者可以放在一起,但是对于微服务来说,每个独自的微服务可能就是一个资源中心。

在oauth2中有几种授权模式:

1、授权码模式

2、密码模式

3、客户端模式

4、简易模式

具体请求流程不是本文中点,我们着重讲解Spring cloud oauth2搭建认证中心。

在oauth中我们通常将他分为认证中心和资源中心。

对于我们的微服务来说,每个独立的微服务即是一个个资源中心,用户想要请求微服务的数据,需要携带认证中心颁发的tocken。

1.引入相关pom依赖

这里我们使用1.5.2.RELEASE的spring boot版本,因为我们会将oauth2交给cloud管理,所以我们同时引入了cloud的依赖,cloud版本使用SR5

org.springframework.boot

spring-boot-starter-parent

1.5.2.RELEASE

org.springframework.cloud

spring-cloud-dependencies

Finchley.SR5

pom

import

org.springframework.cloud

spring-cloud-starter-eureka-server

org.springframework.boot

spring-boot-starter-test

test

net.logstash.logback

logstash-logback-encoder

org.springframework.cloud

spring-cloud-starter-security

true

org.springframework.cloud

spring-cloud-starter-oauth2

org.springframework.security.oauth

spring-security-oauth2

javax.inject

javax.inject

org.springframework.boot

spring-boot-starter-data-redis

mysql

mysql-connector-java

runtime

org.mybatis.spring.boot

mybatis-spring-boot-starter

com.alibaba

fastjson

2.编写spring boot启动类

@SpringBootApplication

@Configuration

@EnableTransactionManagement

@MapperScan(basePackages = {

"com.dahaonetwork.smartfactory.authserver.mapper"

})

public class AuthenticationApplication {

/** 主类 */

public static void main(String[] args) {

SpringApplication.run(AuthenticationApplication.class, args);

}

}

3.声明一个授权服务器

声明一个授权服务器只需要继承 AuthorizationServerConfigurerAdapter,添加

@EnableAuthorizationServer 注解。

@EnableAuthorizationServer 这个注解告诉 Spring 这个应用是 OAuth2 的认证中心。

并且复写如下三个方法:

ClientDetailsServiceConfigurer:这个configurer定义了客户端细节服务。客户详细信息可以被初始化。

AuthorizationServerSecurityConfigurer:在令牌端点上定义了安全约束。

AuthorizationServerEndpointsConfigurer:定义了授权和令牌端点和令牌服务。

配置客户端详细步骤

ClientDetailsServiceConfigurer 类(AuthorizationServerConfigurer类中的一个调用类)可以用来定义一个基于内存的或者JDBC的客户端信息服务。

客户端对象重要的属性有:

clientId:(必须)客户端id。

secret:(对于可信任的客户端是必须的)客户端的私密信息。

scope:客户端的作用域。如果scope未定义或者为空(默认值),则客户端作用域不受限制。

authorizedGrantTypes:授权给客户端使用的权限类型。默认值为空。

authorities:授权给客户端的权限(Spring普通的安全权限)。

在运行的应用中,可以通过直接访问隐藏的存储文件(如:JdbcClientDetailsService中用到的数据库表)或者通过实现ClientDetailsManager 接口(也可以实现ClientDetailsService 接口,或者实现两个接口)来更新客户端信息。

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception{...}

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {...}

@Override

public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {...}

具体代码如下所示:这里我们将tocken信息存储在mysql中,分布式下你可以存储在redis中,全局共享。

@Configuration

@EnableAuthorizationServer

public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter{

@Autowired

@Qualifier("authenticationManagerBean")

private AuthenticationManager authenticationManager;

@Autowired

private RedisConnectionFactory connectionFactory;

@Autowired

private DataSource dataSource;

/**

* @Title: tokenStore

* @Description: 用户验证信息的保存策略,可以存储在内存中,关系型数据库中,redis中

* @param

* @return TokenStore

* @throws

*/

@Bean

public TokenStore tokenStore(){

//return new RedisTokenStore(connectionFactory);

//return new InMemoryTokenStore();

return new JdbcTokenStore(dataSource);

}

@Bean // 声明 ClientDetails实现

public ClientDetailsService clientDetails() {

return new JdbcClientDetailsService(dataSource);

}

/**

*

* 这个方法主要是用于校验注册的第三方客户端的信息,可以存储在数据库中,默认方式是存储在内存中,如下所示,注释掉的代码即为内存中存储的方式

*/

@Override

public void configure(ClientDetailsServiceConfigurer clients) throws Exception{

// clients.inMemory()

// .withClient("client").secret("123456").scopes("read")

// .authorizedGrantTypes("authorization_code", "password", "refresh_token")

// .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT");

// //.authorizedGrantTypes("password","authorization_code","client_credentials","refresh_token");

// //.authorizedGrantTypes("password","refresh_token");

// //.redirectUris("https://www.getpostman.com/oauth2/callback");

// /*redirectUris 关于这个配置项,是在 OAuth2协议中,认证成功后的回调地址,此值同样可以配置多个*/

clients.withClientDetails(clientDetails());

clients.jdbc(dataSource);

}

/**

* 这个方法主要的作用用于控制token的端点等信息

*/

@Override

public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

endpoints.authenticationManager(authenticationManager);

endpoints.tokenStore(tokenStore());

//endpoints.userDetailsService(userService);

// 配置TokenServices参数 可以考虑使用[DefaultTokenServices],它使用随机值创建令牌

DefaultTokenServices tokenServices = new DefaultTokenServices();

tokenServices.setTokenStore(endpoints.getTokenStore());

tokenServices.setSupportRefreshToken(true);

tokenServices.setClientDetailsService(endpoints.getClientDetailsService());

tokenServices.setTokenEnhancer(endpoints.getTokenEnhancer());

tokenServices.setAccessTokenValiditySeconds( (int) TimeUnit.DAYS.toSeconds(30)); // 30天

endpoints.tokenServices(tokenServices);

}

/**

允许表单验证,浏览器直接发送post请求即可获取tocken

*/

@Override

public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {

oauthServer.tokenKeyAccess("permitAll()").checkTokenAccess(

"isAuthenticated()");

oauthServer.allowFormAuthenticationForClients();

}

}

4开启Spring Security的功能

spring security用来验证用户账号密码,对请求路劲做处理等。继承WebSecurityConfigurerAdapter 使用@EnableWebMvcSecurity 注解开启Spring Security的功能。

@EnableWebSecurity

public class SecurityConfig extends WebSecurityConfigurerAdapter{

@Autowired

private MyAuthenticationProvider provider;

@Autowired

private UserDetailsService userService;

/**

* 用户认证

*/

@Override

protected void configure(AuthenticationManagerBuilder auth) throws Exception {

auth.authenticationProvider(provider);

auth.userDetailsService(userService);

// auth.inMemoryAuthentication()

// .withUser("user").password("123456").authorities("ROLE_USER");

}

/**

* 1:

* 请求授权:

* spring security 使用以下匹配器来匹配请求路劲:

* antMatchers:使用ant风格的路劲匹配

* regexMatchers:使用正则表达式匹配路劲

* anyRequest:匹配所有请求路劲

* 在匹配了请求路劲后,需要针对当前用户的信息对请求路劲进行安全处理。

* 2:定制登录行为。

* formLogin()方法定制登录操作

* loginPage()方法定制登录页面访问地址

* defaultSuccessUrl()登录成功后转向的页面

* permitAll()

*/

@Override

protected void configure(HttpSecurity http) throws Exception {

http

.authorizeRequests()

.antMatchers(

StaticParams.PATHREGX.API,

StaticParams.PATHREGX.CSS,

StaticParams.PATHREGX.JS,

StaticParams.PATHREGX.IMG).permitAll()//允许用户任意访问

.anyRequest().authenticated()//其余所有请求都需要认证后才可访问

.and()

.formLogin()

//.loginPage("/login/login.do") /

//.defaultSuccessUrl("/hello2")

.permitAll();//允许用户任意访问

http.csrf().disable();

}

/**

* 密码模式下必须注入的bean authenticationManagerBean

* 认证是由 AuthenticationManager 来管理的,

* 但是真正进行认证的是 AuthenticationManager 中定义的AuthenticationProvider。

* AuthenticationManager 中可以定义有多个 AuthenticationProvider

*/

@Override

@Bean

public AuthenticationManager authenticationManagerBean() throws Exception {

return super.authenticationManagerBean();

}

}

5自定义用户认证实现

认证是由AuthenticationManager 来管理的,

但是真正进行认证的是 AuthenticationManager 中定义的AuthenticationProvider。

AuthenticationManager 中可以定义有多个 AuthenticationProvider,

我们在四步骤中AuthenticationManagerBuilder中添加了当前的Provider 。

@Named

@Component

public class MyAuthenticationProvider extends DaoAuthenticationProvider {

/** 规则校验 */

@Resource(name = "passwordService")

private PasswordService passwordService;

protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();

// 构造函数中注入

@Inject

public MyAuthenticationProvider(UserDetailsService userDetailsService)

{

this.setUserDetailsService(userDetailsService);

}

/**

* 自定义验证方式

*/

@Override

public Authentication authenticate(Authentication authentication) throws AuthenticationException {

String username = authentication.getName();

String password = (String) authentication.getCredentials();

MyUserDetails userDetails = (MyUserDetails)

this.getUserDetailsService().loadUserByUsername(username);

//按登录规则校验用户

passwordService.validateRules(userDetails.getUser(), password);

Collection extends GrantedAuthority> authorities = userDetails.getAuthorities();

Authentication authenticationToken = new UsernamePasswordAuthenticationToken(JSON.toJSONString(userDetails,SerializerFeature.WriteMapNullValue), password, authorities);

return authenticationToken;

}

@Override

public boolean supports(Class> arg0) {

return true;

}

}

6自定义UserDetailsService

自定义需要实现UserDetailsService接口,并且重写loadUserByUsername方法。返回的用户信息需要实现UserDatails接口。

@Service("userInfo")

public class UserInfoService implements UserDetailsService{

@Autowired

private UserMapper userMapper;

@Override

public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {

// TODO Auto-generated method stub

Map paramMap=new HashMap();

paramMap.put("loginId", username);

User user=userMapper.getUserByloginIds(paramMap);

if(user ==null) {

throw new BadCredentialsException(Constants.getReturnStr(Constants.USER_NOT_FOUND, Constants.USER_NOT_FOUND_TIPS));

}

MyUserDetails userDetails = new MyUserDetails();

userDetails.setUserName(username);

userDetails.setPassword(user.getPassword());

userDetails.setUser(user);

return userDetails;

}

}

public class MyUserDetails implements UserDetails{

private static final long seriaVersionUID=1L;

private String userName;

private String password;

private User user;

public String getUserName() {

return userName;

}

public void setUserName(String userName) {

this.userName = userName;

}

public void setPassword(String password) {

this.password = password;

}

public User getUser() {

return user;

}

public void setUser(User user) {

this.user = user;

}

/**

* 重写getAuthorities方法,将用户的角色作为权限

*/

@Override

public Collection extends GrantedAuthority> getAuthorities() {

//TODO 后续带完善

return AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_SUPER");

}

@Override

public String getPassword() {

return password;

}

@Override

public String getUsername() {

return userName;

}

@Override

public boolean isAccountNonExpired() {

return true;

}

@Override

public boolean isAccountNonLocked() {

return true;

}

@Override

public boolean isCredentialsNonExpired() {

return true;

}

@Override

public boolean isEnabled() {

return true;

}

}

7相关数据库表结构

8相关配置文件

spring.application.name=oauth-server

server.port=8043

server.context-path=/uaa

logging.level.org.springframework.security=DEBUG

security.oauth2.resource.serviceId= ${PREFIX:}resource

security.oauth2.resource.filter-order=3

database.url=jdbc:mysql://192.168.7.175:3306/oauth2

spring.datasource.url=${database.url}?useUnicode\=true&characterEncoding\=UTF-8&useOldAliasMetadataBehavior\=true

spring.datasource.username=devdb

spring.datasource.password=

spring.datasource.driver-class-name=com.mysql.jdbc.Driver

logging.level.root=info

logging.level.com.dahaonetwork.smartfactory.authserver=debug

logging.level.org.springframework.security=info

#mybatis show sql

logging.level.org.springframework=WARN

spring.thymeleaf.cache=false

spring.jpa.hibernate.ddl-auto=update

spring.jpa.show-sql=true

mybatis.mapper-locations=classpath:mapper/*.xml

9测试

这里我们使用密码模式来获取tocken:

d3901772c95a

这样认证服务器就搭建完成了,浏览器只需要携带tocken就可以访问资源服务器上的相关信息。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值