Profile
The main content of this article is the construction of the Spring Cloud Licensing service, using JWT certification.
GitHub Address: Https://github.com/fp2952/spring-cloud-base/tree/master/auth-center/auth-center-provider
Add dependency
OAuth2 extension of Spring Security and security
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-security</artifactId> </dependency> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-oauth2</artifactId> </dependency>
Start class annotations
Start class Add @EnableAuthorizationServer
annotations
@SpringCloudApplication@EnableAuthorizationServer@EnableFeignClients("com.peng.main.client")public class AuthCenterProviderApplication { public static void main(String[] args){ SpringApplication.run(AuthCenterProviderApplication.class, args); }}
Oauth2 Configuration Class Authorizationserverconfigureradapter
In Authorizationserverconfigureradapter:
- Clientdetailsserviceconfigurer: Used to configure the client detail service (Clientdetailsservice), the client details are initialized here, You can write the client details dead here or through a database to store the details of the fetch.
- Authorizationserversecurityconfigurer: The security constraint used to configure the token endpoint (token Endpoint).
- Authorizationserverendpointsconfigurer: The access endpoint and token service (token services) used to configure authorization (authorization) and token (tokens).
The main configuration is as follows:
Configuring Client Detail Information
Clientdetailsserviceconfigurer (a callback configuration entry for Authorizationserverconfigurer) Ability to use memory or JDBC for client detail Services (clientdetailsservice), Spring Security OAUTH2 is configured by writing the @configuration class inheritance Authorizationserverconfigureradapter, and then overriding the Void Configure ( Clientdetailsserviceconfigurer clients) methods, such as:
@Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { // 使用JdbcClientDetailsService客户端详情服务 clients.withClientDetails(new JdbcClientDetailsService(dataSource)); }
Here, the client details service is implemented using JDBC, the data source DataSource does not narrate, using the Framework default table, the schema link:
Https://github.com/spring-projects/spring-security-oauth/blob/master/spring-security-oauth2/src/test/resources/schema.sql
Configuring token Management (Jwtaccesstokenconverter)
The
Jwtaccesstokenconverter is the converter used to generate tokens, and the token token is signed by default, and the resource server needs to verify the signature. There are two ways to encrypt and verify:
Symmetric encryption, asymmetric encryption (public key)
Symmetric encryption requires the authorization server and the resource server to store the same key value, and asymmetric encryption can use key encryption, exposing the public key to the resource server verification, the use of asymmetric encryption in this article, Configured on Authorizationserverconfigureradapter as follows:
@Override public void Configure (Authorizationserverendpointsconfigurer endpoints) {Endpoints.aut Henticationmanager (AuthenticationManager)//Configure Jwtaccesstoken Converter. Accesstokenconverter (Jwtac Cesstokenconverter ())///Refresh_token requires Userdetailsservice. Reuserefreshtokens (false). Userde Tailsservice (Userdetailsservice); . Tokenstore (Getjdbctokenstore ()); /** * Use an asymmetric encryption algorithm to sign tokens * @return */@Bean public jwtaccesstokenconverter Jwtaccesstokenconverte R () {Final Jwtaccesstokenconverter converter = new Jwtaccesstoken (); Import certificate Keystorekeyfactory keystorekeyfactory = new Keystorekeyfactory (New Classpathresource ("Keysto Re.jks ")," Mypass ". ToCharArray ()); Converter.setkeypair (Keystorekeyfactory.getkeypair ("mytest")); return converter; }
Generate the JKS certificate file from the JDK tool and put the KEYSTORE.JKS into the resource directory
keytool -genkeypair -alias mytest -keyalg RSA -keypass mypass -keystore keystore.jks -storepass mypass
Here we customize Jwtaccesstoken for adding additional user information
/** * Created by fp295 on 2018/4/16. * Custom Jwtaccesstoken Converter */public class Jwtaccesstoken extends Jwtaccesstokenconverter {/** * Generate token * @param a Ccesstoken * @param authentication * @return * */@Override public oauth2accesstoken enhance (oauth2accesst Oken Accesstoken, oauth2authentication authentication) {Defaultoauth2accesstoken Defaultoauth2accesstoken = new De Faultoauth2accesstoken (Accesstoken); Set additional user information Baseuser Baseuser = ((Baseuserdetail) Authentication.getprincipal ()). Getbaseuser (); Baseuser.setpassword (NULL); Add user information to token extra information defaultoauth2accesstoken.getadditionalinformation (). Put (Constant.user_info, baseuser); Return Super.enhance (Defaultoauth2accesstoken, authentication); }/** * Parse token * @param value * @param map * @return */@Override public Oauth2accesstoken E Xtractaccesstoken (String value, map<string,?> Map) {Oauth2accesstoken oauth2accessToken = Super.extractaccesstoken (value, map); Convertdata (Oauth2accesstoken, Oauth2accesstoken.getadditionalinformation ()); return oauth2accesstoken; } private void Convertdata (Oauth2accesstoken accesstoken, map<string,?> Map) {accesstoken.getadditional Information (). Put (Constant.user_info,convertuserdata (Map.get (Constant.user_info))); } private Baseuser Convertuserdata (Object map) {String json = Jsonutils.deserializer (map); Baseuser user = Jsonutils.serializable (JSON, baseuser.class); return user; }}
The
Jwtaccesstoken class obtains user information from the Getprincipal in the authentication (actually the Userdetails interface), so we need to implement our own userdetails
/** * Created by fp295 on 2018/4/29. * Packaging Org.springframework.security.core.userdetails.User Class */public classes Baseuserdetail implements Userdetails, Credentialscontainer {private final baseuser baseuser; Private final Org.springframework.security.core.userdetails.User User; Public Baseuserdetail (Baseuser baseuser, user user) {this.baseuser = Baseuser; This.user = user; } @Override public void Erasecredentials () {user.erasecredentials (); } @Override public collection<? Extends Grantedauthority> getauthorities () {return user.getauthorities (); } @Override Public String GetPassword () {return User.getpassword (); } @Override Public String GetUserName () {return user.getusername (); } @Override public Boolean isaccountnonexpired () {return user.isaccountnonexpired (); } @Override public Boolean isaccountnonlocked () {return user.isaccountnonlocked (); } @Override public Boolean iscredentialsnonexpired () {return user.iscredentialsnonexpired (); } @Override public Boolean isenabled () {return user.isenabled (); } public Baseuser Getbaseuser () {return baseuser; }}
Authorized Endpoint Open
@Override public void configure(AuthorizationServerSecurityConfigurer oauthServer) { oauthServer // 开启/oauth/token_key验证端口无权限访问 .tokenKeyAccess("permitAll()") // 开启/oauth/check_token验证端口认证权限访问 .checkTokenAccess("isAuthenticated()"); }
Security Configuration
Need to configure Daoauthenticationprovider, Userdetailservice, etc.
@Configuration @order (managementserverproperties.access_override_order) public class Websecurityconfig extends Websecurityconfigureradapter {//auto-inject userdetailsservice @Autowired private Baseuserdetailservice baseuserdetails Ervice; @Override public void Configure (Httpsecurity http) throws Exception {http//config landing page/login and allow access . Formlogin (). Permitall ()//Logout page. and (). Logout (). Logouturl ("/logout"). Logoutsuccessurl ("/") All remaining requests require authentication. and (). Authorizerequests (). Anyrequest (). Authenticated ()// Since we are using JWT, we do not need csrf. and (). CSRF (). disable (); }/** * User authentication * @param auth * * * @Override public void Configure (Authenticationmanagerbuilder auth) { Auth.authenticationprovider (Daoauthenticationprovider ()); } @Bean Public Daoauthenticationprovider Daoauthenticationprovider () {Daoauthenticationprovider Provider = NE W DaoauthenticatiOnprovider (); Set Userdetailsservice provider.setuserdetailsservice (Baseuserdetailservice); Suppress hidden user not found exception provider.sethideusernotfoundexceptions (false); Use Bcrypt for password hash provider.setpasswordencoder (new Bcryptpasswordencoder (6)); return provider; }}
Userdetailsservice implementation
@Servicepublic class Baseuserdetailservice implements Userdetailsservice {private Logger Logger = Loggerfactory.getlog GER (This.getclass ()); @Autowired private Baseuserservice Baseuserservice; @Autowired private Baseroleservice Baseroleservice; @Override public userdetails loaduserbyusername (String username) throws Usernamenotfoundexception {//Call FEIGNCL ient query user responsedata<baseuser> baseuserresponsedata = baseuserservice.getuserbyusername (username); if (baseuserresponsedata.getdata () = = NULL | |! ResponseCode.SUCCESS.getCode (). Equals (Baseuserresponsedata.getcode ())) {Logger.error ("The user is not found, user name:" + username); throw new Usernamenotfoundexception ("Could not find the user, user name:" + username); } baseuser Baseuser = Baseuserresponsedata.getdata (); Call feignclient query role responsedata<list<baserole>> baserolelistresponsedata = BaseRoleService.getRoleByU Serid (Baseuser.getid ()); List<baserole> ROles; if (baserolelistresponsedata.getdata () = = NULL | | ! ResponseCode.SUCCESS.getCode (). Equals (Baserolelistresponsedata.getcode ())) {Logger.error ("Query role failed! "); roles = new arraylist<> (); }else {roles = Baserolelistresponsedata.getdata (); }//Get a list of user rights list<grantedauthority> authorities = new ArrayList (); Roles.foreach (E--{//store user, role information to grantedauthority, and put to grantedauthority list grantedauthority Authori ty = new Simplegrantedauthority (E.getrolecode ()); Authorities.add (authority); }); Org.springframework.security.core.userdetails.User user = new Org.springframework.security.core with information about users ' rights . userdetails. User (Baseuser.getusername (), Baseuser.getpassword (), IsActive (Baseuser.getactive ()), True, true, true, auth Orities); return new Baseuserdetail (Baseuser, user); } private Boolean isActive (int active) {REturn active = = 1? True:false; }}
Authorization Server Authentication
http://127.0.0.1:8080/oauth/authorize?client_id=clientId&response_type=code&redirect_uri=www.baidu.com
Note: client_id: For client_id stored in the database, Response_type: Write Dead Code
- Enter the simple landing page of spring security after the link returns,
- Enter the account password, for the implementation of the Userdetailsservice to get the user, click Login,
- Go to the Simple authorization page, click Authorize,
- Redirect to Redirect_uri with the code parameter:
http://www.baidu.com?code=rTKETX
- Post request for token:
Note that the request header is added here, and Authorization
the value is Basic xxx
xxx for client_id:client_secret
the base64 encoding, which returns:
Spring Cloud OAuth2 (i) Build a licensing service